summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorManuel Bentele2020-10-23 15:18:01 +0200
committerManuel Bentele2020-10-23 15:18:01 +0200
commitdbb41ce2b7f309d394054a6bd1e33afd578798a5 (patch)
tree6a31092063d9f2fb5ac5720ec6759040e793c3d5 /src
parentSet Linux kernel version to unknown if it is not detectable (diff)
downloadxloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.gz
xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.xz
xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.zip
Move the source code of all xloop components to the common 'src' directory
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/kernel/CMakeLists.txt73
-rw-r--r--src/kernel/Kbuild12
-rw-r--r--src/kernel/cmake/kernel.cmake56
-rw-r--r--src/kernel/tests/CMakeLists.txt14
-rw-r--r--src/kernel/tests/include/config.h.in591
-rw-r--r--src/kernel/tests/include/ipcmsg.h68
-rw-r--r--src/kernel/tests/include/ipcsem.h55
-rw-r--r--src/kernel/tests/include/ipcshm.h54
-rw-r--r--src/kernel/tests/include/lapi/abisize.h31
-rw-r--r--src/kernel/tests/include/lapi/acct.h74
-rw-r--r--src/kernel/tests/include/lapi/bpf.h591
-rw-r--r--src/kernel/tests/include/lapi/capability.h51
-rw-r--r--src/kernel/tests/include/lapi/clone.h49
-rw-r--r--src/kernel/tests/include/lapi/common_timers.h81
-rw-r--r--src/kernel/tests/include/lapi/cpuset.h51
-rw-r--r--src/kernel/tests/include/lapi/cryptouser.h182
-rw-r--r--src/kernel/tests/include/lapi/dccp.h17
-rw-r--r--src/kernel/tests/include/lapi/epoll.h13
-rw-r--r--src/kernel/tests/include/lapi/execveat.h22
-rw-r--r--src/kernel/tests/include/lapi/fallocate.h60
-rw-r--r--src/kernel/tests/include/lapi/fcntl.h139
-rw-r--r--src/kernel/tests/include/lapi/fnmatch.h14
-rw-r--r--src/kernel/tests/include/lapi/fs.h66
-rw-r--r--src/kernel/tests/include/lapi/fsmount.h145
-rw-r--r--src/kernel/tests/include/lapi/futex.h13
-rw-r--r--src/kernel/tests/include/lapi/getrandom.h30
-rw-r--r--src/kernel/tests/include/lapi/if_alg.h59
-rw-r--r--src/kernel/tests/include/lapi/if_ether.h19
-rw-r--r--src/kernel/tests/include/lapi/if_packet.h50
-rw-r--r--src/kernel/tests/include/lapi/io_pgetevents.h35
-rw-r--r--src/kernel/tests/include/lapi/io_uring.h299
-rw-r--r--src/kernel/tests/include/lapi/ioctl.h40
-rw-r--r--src/kernel/tests/include/lapi/ioctl_ns.h28
-rw-r--r--src/kernel/tests/include/lapi/iovec.h20
-rw-r--r--src/kernel/tests/include/lapi/ipcbuf.h195
-rw-r--r--src/kernel/tests/include/lapi/keyctl.h178
-rw-r--r--src/kernel/tests/include/lapi/membarrier.h30
-rw-r--r--src/kernel/tests/include/lapi/memfd.h50
-rw-r--r--src/kernel/tests/include/lapi/mkdirat.h20
-rw-r--r--src/kernel/tests/include/lapi/mlock2.h16
-rw-r--r--src/kernel/tests/include/lapi/mmap.h87
-rw-r--r--src/kernel/tests/include/lapi/mount.h33
-rw-r--r--src/kernel/tests/include/lapi/msg.h15
-rw-r--r--src/kernel/tests/include/lapi/msgbuf.h306
-rw-r--r--src/kernel/tests/include/lapi/namespaces_constants.h31
-rw-r--r--src/kernel/tests/include/lapi/netinet_in.h23
-rw-r--r--src/kernel/tests/include/lapi/openat2.h72
-rw-r--r--src/kernel/tests/include/lapi/personality.h23
-rw-r--r--src/kernel/tests/include/lapi/pidfd_open.h24
-rw-r--r--src/kernel/tests/include/lapi/pidfd_send_signal.h27
-rw-r--r--src/kernel/tests/include/lapi/posix_clocks.h42
-rw-r--r--src/kernel/tests/include/lapi/posix_types.h21
-rw-r--r--src/kernel/tests/include/lapi/prctl.h55
-rw-r--r--src/kernel/tests/include/lapi/preadv2.h30
-rw-r--r--src/kernel/tests/include/lapi/pwritev2.h26
-rw-r--r--src/kernel/tests/include/lapi/quotactl.h78
-rw-r--r--src/kernel/tests/include/lapi/readdir.h19
-rw-r--r--src/kernel/tests/include/lapi/readlinkat.h20
-rw-r--r--src/kernel/tests/include/lapi/renameat.h23
-rw-r--r--src/kernel/tests/include/lapi/rt_sigaction.h245
-rw-r--r--src/kernel/tests/include/lapi/safe_rt_signal.h50
-rw-r--r--src/kernel/tests/include/lapi/sched.h62
-rw-r--r--src/kernel/tests/include/lapi/sctp.h17
-rw-r--r--src/kernel/tests/include/lapi/seccomp.h40
-rw-r--r--src/kernel/tests/include/lapi/securebits.h17
-rw-r--r--src/kernel/tests/include/lapi/seek.h19
-rw-r--r--src/kernel/tests/include/lapi/sembuf.h234
-rw-r--r--src/kernel/tests/include/lapi/semun.h22
-rw-r--r--src/kernel/tests/include/lapi/setns.h20
-rw-r--r--src/kernel/tests/include/lapi/shm.h13
-rw-r--r--src/kernel/tests/include/lapi/shmbuf.h273
-rw-r--r--src/kernel/tests/include/lapi/signal.h24
-rw-r--r--src/kernel/tests/include/lapi/socket.h72
-rw-r--r--src/kernel/tests/include/lapi/splice.h22
-rw-r--r--src/kernel/tests/include/lapi/stat.h257
-rw-r--r--src/kernel/tests/include/lapi/sync_file_range.h58
-rw-r--r--src/kernel/tests/include/lapi/syncfs.h21
-rw-r--r--src/kernel/tests/include/lapi/syscalls.h19964
-rw-r--r--src/kernel/tests/include/lapi/tcp.h19
-rw-r--r--src/kernel/tests/include/lapi/tee.h20
-rw-r--r--src/kernel/tests/include/lapi/termbits.h13
-rw-r--r--src/kernel/tests/include/lapi/timerfd.h41
-rw-r--r--src/kernel/tests/include/lapi/timex.h30
-rw-r--r--src/kernel/tests/include/lapi/tty.h21
-rw-r--r--src/kernel/tests/include/lapi/udp.h18
-rw-r--r--src/kernel/tests/include/lapi/ustat.h22
-rw-r--r--src/kernel/tests/include/lapi/utime.h16
-rw-r--r--src/kernel/tests/include/lapi/utsname.h16
-rw-r--r--src/kernel/tests/include/lapi/vmsplice.h23
-rw-r--r--src/kernel/tests/include/lapi/xfrm.h17
-rw-r--r--src/kernel/tests/include/lapi/xloop.h55
-rw-r--r--src/kernel/tests/include/libmsgctl.h39
-rw-r--r--src/kernel/tests/include/libnewipc.h59
-rw-r--r--src/kernel/tests/include/libsigwait.h44
-rw-r--r--src/kernel/tests/include/old/cleanup.c47
-rw-r--r--src/kernel/tests/include/old/ltp_cpuid.h35
-rw-r--r--src/kernel/tests/include/old/ltp_priv.h74
-rw-r--r--src/kernel/tests/include/old/ltp_signal.h56
-rw-r--r--src/kernel/tests/include/old/old_checkpoint.h59
-rw-r--r--src/kernel/tests/include/old/old_device.h84
-rw-r--r--src/kernel/tests/include/old/old_module.h72
-rw-r--r--src/kernel/tests/include/old/old_resource.h55
-rw-r--r--src/kernel/tests/include/old/old_safe_file_ops.h64
-rw-r--r--src/kernel/tests/include/old/old_safe_net.h50
-rw-r--r--src/kernel/tests/include/old/old_safe_stdio.h37
-rw-r--r--src/kernel/tests/include/old/old_tmpdir.h56
-rw-r--r--src/kernel/tests/include/old/random_range.h45
-rw-r--r--src/kernel/tests/include/old/safe_macros.h340
-rw-r--r--src/kernel/tests/include/old/test.h214
-rw-r--r--src/kernel/tests/include/old/tlibio.h161
-rw-r--r--src/kernel/tests/include/old/usctest.h105
-rw-r--r--src/kernel/tests/include/parse_vdso.h41
-rw-r--r--src/kernel/tests/include/safe_file_ops_fn.h83
-rw-r--r--src/kernel/tests/include/safe_macros_fn.h187
-rw-r--r--src/kernel/tests/include/safe_net_fn.h81
-rw-r--r--src/kernel/tests/include/safe_stdio_fn.h35
-rw-r--r--src/kernel/tests/include/tst_af_alg.h168
-rw-r--r--src/kernel/tests/include/tst_ansi_color.h22
-rw-r--r--src/kernel/tests/include/tst_assert.h65
-rw-r--r--src/kernel/tests/include/tst_atomic.h334
-rw-r--r--src/kernel/tests/include/tst_buffers.h63
-rw-r--r--src/kernel/tests/include/tst_capability.h83
-rw-r--r--src/kernel/tests/include/tst_cgroup.h45
-rw-r--r--src/kernel/tests/include/tst_checkpoint.h28
-rw-r--r--src/kernel/tests/include/tst_checkpoint_fn.h42
-rw-r--r--src/kernel/tests/include/tst_checksum.h16
-rw-r--r--src/kernel/tests/include/tst_clocks.h23
-rw-r--r--src/kernel/tests/include/tst_clone.h21
-rw-r--r--src/kernel/tests/include/tst_cmd.h94
-rw-r--r--src/kernel/tests/include/tst_common.h86
-rw-r--r--src/kernel/tests/include/tst_coredump.h18
-rw-r--r--src/kernel/tests/include/tst_cpu.h19
-rw-r--r--src/kernel/tests/include/tst_crypto.h112
-rw-r--r--src/kernel/tests/include/tst_device.h108
-rw-r--r--src/kernel/tests/include/tst_fs.h246
-rw-r--r--src/kernel/tests/include/tst_fuzzy_sync.h776
-rw-r--r--src/kernel/tests/include/tst_get_bad_addr.h12
-rw-r--r--src/kernel/tests/include/tst_hugepage.h37
-rw-r--r--src/kernel/tests/include/tst_kconfig.h56
-rw-r--r--src/kernel/tests/include/tst_kernel.h21
-rw-r--r--src/kernel/tests/include/tst_kvercmp.h44
-rw-r--r--src/kernel/tests/include/tst_lockdown.h10
-rw-r--r--src/kernel/tests/include/tst_memutils.h22
-rw-r--r--src/kernel/tests/include/tst_minmax.h24
-rw-r--r--src/kernel/tests/include/tst_mkfs.h22
-rw-r--r--src/kernel/tests/include/tst_net.h35
-rw-r--r--src/kernel/tests/include/tst_netlink.h88
-rw-r--r--src/kernel/tests/include/tst_numa.h112
-rw-r--r--src/kernel/tests/include/tst_path_has_mnt_flags.h29
-rw-r--r--src/kernel/tests/include/tst_pid.h43
-rw-r--r--src/kernel/tests/include/tst_private.h32
-rw-r--r--src/kernel/tests/include/tst_process_state.h53
-rw-r--r--src/kernel/tests/include/tst_res_flags.h23
-rw-r--r--src/kernel/tests/include/tst_safe_clocks.h157
-rw-r--r--src/kernel/tests/include/tst_safe_file_ops.h49
-rw-r--r--src/kernel/tests/include/tst_safe_macros.h606
-rw-r--r--src/kernel/tests/include/tst_safe_net.h79
-rw-r--r--src/kernel/tests/include/tst_safe_posix_ipc.h47
-rw-r--r--src/kernel/tests/include/tst_safe_prw.h47
-rw-r--r--src/kernel/tests/include/tst_safe_pthread.h33
-rw-r--r--src/kernel/tests/include/tst_safe_stdio.h24
-rw-r--r--src/kernel/tests/include/tst_safe_sysv_ipc.h54
-rw-r--r--src/kernel/tests/include/tst_safe_timerfd.h32
-rw-r--r--src/kernel/tests/include/tst_sig_proc.h12
-rw-r--r--src/kernel/tests/include/tst_sys_conf.h19
-rw-r--r--src/kernel/tests/include/tst_taint.h98
-rw-r--r--src/kernel/tests/include/tst_test.h335
-rw-r--r--src/kernel/tests/include/tst_timer.h1055
-rw-r--r--src/kernel/tests/include/tst_timer_test.h45
-rw-r--r--src/kernel/tests/include/tst_uinput.h47
-rw-r--r--src/kernel/tests/include/tst_wallclock.h15
-rw-r--r--src/kernel/tests/lib/CMakeLists.txt70
-rw-r--r--src/kernel/tests/lib/cloner.c175
-rw-r--r--src/kernel/tests/lib/errnos.h186
-rw-r--r--src/kernel/tests/lib/get_path.c103
-rw-r--r--src/kernel/tests/lib/parse_opts.c621
-rw-r--r--src/kernel/tests/lib/random_range.c892
-rw-r--r--src/kernel/tests/lib/safe_file_ops.c422
-rw-r--r--src/kernel/tests/lib/safe_macros.c1109
-rw-r--r--src/kernel/tests/lib/safe_net.c459
-rw-r--r--src/kernel/tests/lib/safe_pthread.c43
-rw-r--r--src/kernel/tests/lib/safe_stdio.c97
-rw-r--r--src/kernel/tests/lib/self_exec.c225
-rw-r--r--src/kernel/tests/lib/signame.h106
-rw-r--r--src/kernel/tests/lib/tlibio.c2161
-rw-r--r--src/kernel/tests/lib/tst_af_alg.c212
-rw-r--r--src/kernel/tests/lib/tst_ansi_color.c64
-rw-r--r--src/kernel/tests/lib/tst_assert.c83
-rw-r--r--src/kernel/tests/lib/tst_buffers.c143
-rw-r--r--src/kernel/tests/lib/tst_capability.c90
-rw-r--r--src/kernel/tests/lib/tst_cgroup.c452
-rw-r--r--src/kernel/tests/lib/tst_checkpoint.c164
-rw-r--r--src/kernel/tests/lib/tst_checksum.c81
-rw-r--r--src/kernel/tests/lib/tst_clocks.c144
-rw-r--r--src/kernel/tests/lib/tst_cmd.c178
-rw-r--r--src/kernel/tests/lib/tst_coredump.c35
-rw-r--r--src/kernel/tests/lib/tst_cpu.c73
-rw-r--r--src/kernel/tests/lib/tst_crypto.c110
-rw-r--r--src/kernel/tests/lib/tst_device.c531
-rw-r--r--src/kernel/tests/lib/tst_dir_is_empty.c49
-rw-r--r--src/kernel/tests/lib/tst_fill_file.c118
-rw-r--r--src/kernel/tests/lib/tst_fill_fs.c68
-rw-r--r--src/kernel/tests/lib/tst_fs_has_free.c44
-rw-r--r--src/kernel/tests/lib/tst_fs_link_count.c183
-rw-r--r--src/kernel/tests/lib/tst_fs_setup.c49
-rw-r--r--src/kernel/tests/lib/tst_fs_type.c90
-rw-r--r--src/kernel/tests/lib/tst_get_bad_addr.c31
-rw-r--r--src/kernel/tests/lib/tst_hugepage.c61
-rw-r--r--src/kernel/tests/lib/tst_ioctl.c37
-rw-r--r--src/kernel/tests/lib/tst_kconfig.c285
-rw-r--r--src/kernel/tests/lib/tst_kernel.c100
-rw-r--r--src/kernel/tests/lib/tst_kvercmp.c195
-rw-r--r--src/kernel/tests/lib/tst_lockdown.c30
-rw-r--r--src/kernel/tests/lib/tst_memutils.c62
-rw-r--r--src/kernel/tests/lib/tst_mkfs.c117
-rw-r--r--src/kernel/tests/lib/tst_module.c124
-rw-r--r--src/kernel/tests/lib/tst_net.c221
-rw-r--r--src/kernel/tests/lib/tst_parse_opts.c36
-rw-r--r--src/kernel/tests/lib/tst_path_has_mnt_flags.c83
-rw-r--r--src/kernel/tests/lib/tst_pid.c64
-rw-r--r--src/kernel/tests/lib/tst_process_state.c86
-rw-r--r--src/kernel/tests/lib/tst_res.c606
-rw-r--r--src/kernel/tests/lib/tst_resource.c138
-rw-r--r--src/kernel/tests/lib/tst_safe_macros.c333
-rw-r--r--src/kernel/tests/lib/tst_safe_sysv_ipc.c145
-rw-r--r--src/kernel/tests/lib/tst_safe_timerfd.c56
-rw-r--r--src/kernel/tests/lib/tst_sig.c255
-rw-r--r--src/kernel/tests/lib/tst_sig_proc.c31
-rw-r--r--src/kernel/tests/lib/tst_status.c50
-rw-r--r--src/kernel/tests/lib/tst_supported_fs_types.c111
-rw-r--r--src/kernel/tests/lib/tst_sys_conf.c105
-rw-r--r--src/kernel/tests/lib/tst_taint.c107
-rw-r--r--src/kernel/tests/lib/tst_test.c1387
-rw-r--r--src/kernel/tests/lib/tst_timer.c59
-rw-r--r--src/kernel/tests/lib/tst_timer_test.c472
-rw-r--r--src/kernel/tests/lib/tst_tmpdir.c347
-rw-r--r--src/kernel/tests/lib/tst_virt.c132
-rw-r--r--src/kernel/tests/lib/tst_wallclock.c60
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/CMakeLists.txt45
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop01.c156
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop02.c165
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop03.c76
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop04.c99
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop05.c156
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop06.c144
-rw-r--r--src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop07.c96
-rw-r--r--src/kernel/uapi_xloop.h125
-rw-r--r--src/kernel/udev/50-xloop.rules56
-rw-r--r--src/kernel/xloop_file_fmt.c356
-rw-r--r--src/kernel/xloop_file_fmt.h388
-rw-r--r--src/kernel/xloop_file_fmt_qcow_cache.c219
-rw-r--r--src/kernel/xloop_file_fmt_qcow_cache.h51
-rw-r--r--src/kernel/xloop_file_fmt_qcow_cluster.c353
-rw-r--r--src/kernel/xloop_file_fmt_qcow_cluster.h22
-rw-r--r--src/kernel/xloop_file_fmt_qcow_main.c1283
-rw-r--r--src/kernel/xloop_file_fmt_qcow_main.h646
-rw-r--r--src/kernel/xloop_file_fmt_raw.c476
-rw-r--r--src/kernel/xloop_main.c2245
-rw-r--r--src/kernel/xloop_main.h107
-rw-r--r--src/utils/CMakeLists.txt27
-rw-r--r--src/utils/bash-completion/xlosetup85
-rw-r--r--src/utils/config.h.in897
-rw-r--r--src/utils/include/all-io.h81
-rw-r--r--src/utils/include/bitops.h150
-rw-r--r--src/utils/include/blkdev.h151
-rw-r--r--src/utils/include/c.h427
-rw-r--r--src/utils/include/canonicalize.h32
-rw-r--r--src/utils/include/caputils.h34
-rw-r--r--src/utils/include/carefulputc.h155
-rw-r--r--src/utils/include/cctype.h325
-rw-r--r--src/utils/include/closestream.h110
-rw-r--r--src/utils/include/color-names.h44
-rw-r--r--src/utils/include/colors.h73
-rw-r--r--src/utils/include/cpuset.h99
-rw-r--r--src/utils/include/crc32.h12
-rw-r--r--src/utils/include/crc32c.h9
-rw-r--r--src/utils/include/debug.h181
-rw-r--r--src/utils/include/debugobj.h22
-rw-r--r--src/utils/include/encode.h14
-rw-r--r--src/utils/include/env.h35
-rw-r--r--src/utils/include/exec_shell.h6
-rw-r--r--src/utils/include/exitcodes.h25
-rw-r--r--src/utils/include/fileutils.h77
-rw-r--r--src/utils/include/fuzz.h9
-rw-r--r--src/utils/include/idcache.h28
-rw-r--r--src/utils/include/ismounted.h14
-rw-r--r--src/utils/include/iso9660.h58
-rw-r--r--src/utils/include/linux_version.h14
-rw-r--r--src/utils/include/list.h361
-rw-r--r--src/utils/include/loopdev.h222
-rw-r--r--src/utils/include/mangle.h28
-rw-r--r--src/utils/include/match.h12
-rw-r--r--src/utils/include/mbsalign.h66
-rw-r--r--src/utils/include/mbsedit.h32
-rw-r--r--src/utils/include/md5.h24
-rw-r--r--src/utils/include/minix.h85
-rw-r--r--src/utils/include/monotonic.h22
-rw-r--r--src/utils/include/namespace.h56
-rw-r--r--src/utils/include/nls.h153
-rw-r--r--src/utils/include/optutils.h107
-rw-r--r--src/utils/include/pager.h9
-rw-r--r--src/utils/include/partx.h63
-rw-r--r--src/utils/include/path.h135
-rw-r--r--src/utils/include/pathnames.h210
-rw-r--r--src/utils/include/pidfd-utils.h28
-rw-r--r--src/utils/include/plymouth-ctrl.h65
-rw-r--r--src/utils/include/procutils.h34
-rw-r--r--src/utils/include/pt-bsd.h156
-rw-r--r--src/utils/include/pt-gpt-partnames.h160
-rw-r--r--src/utils/include/pt-mbr-partnames.h112
-rw-r--r--src/utils/include/pt-mbr.h187
-rw-r--r--src/utils/include/pt-sgi.h115
-rw-r--r--src/utils/include/pt-sun.h90
-rw-r--r--src/utils/include/pty-session.h110
-rw-r--r--src/utils/include/pwdutils.h14
-rw-r--r--src/utils/include/randutils.h17
-rw-r--r--src/utils/include/rpmatch.h13
-rw-r--r--src/utils/include/setproctitle.h7
-rw-r--r--src/utils/include/sha1.h27
-rw-r--r--src/utils/include/signames.h8
-rw-r--r--src/utils/include/statfs_magic.h100
-rw-r--r--src/utils/include/strutils.h333
-rw-r--r--src/utils/include/strv.h55
-rw-r--r--src/utils/include/swapheader.h23
-rw-r--r--src/utils/include/swapprober.h9
-rw-r--r--src/utils/include/sysfs.h113
-rw-r--r--src/utils/include/timer.h22
-rw-r--r--src/utils/include/timeutils.h92
-rw-r--r--src/utils/include/ttyutils.h205
-rw-r--r--src/utils/include/widechar.h47
-rw-r--r--src/utils/include/xalloc.h139
-rw-r--r--src/utils/lib/CMakeLists.txt44
-rw-r--r--src/utils/lib/blkdev.c452
-rw-r--r--src/utils/lib/canonicalize.c250
-rw-r--r--src/utils/lib/caputils.c45
-rw-r--r--src/utils/lib/color-names.c64
-rw-r--r--src/utils/lib/colors.c907
-rw-r--r--src/utils/lib/cpuset.c413
-rw-r--r--src/utils/lib/crc32.c142
-rw-r--r--src/utils/lib/crc32c.c102
-rw-r--r--src/utils/lib/encode.c79
-rw-r--r--src/utils/lib/env.c238
-rw-r--r--src/utils/lib/exec_shell.c51
-rw-r--r--src/utils/lib/fileutils.c246
-rw-r--r--src/utils/lib/idcache.c117
-rw-r--r--src/utils/lib/ismounted.c396
-rw-r--r--src/utils/lib/langinfo.c124
-rw-r--r--src/utils/lib/linux_version.c71
-rw-r--r--src/utils/lib/loopdev.c1914
-rw-r--r--src/utils/lib/mangle.c169
-rw-r--r--src/utils/lib/match.c53
-rw-r--r--src/utils/lib/mbsalign.c627
-rw-r--r--src/utils/lib/mbsedit.c225
-rw-r--r--src/utils/lib/md5.c257
-rw-r--r--src/utils/lib/monotonic.c81
-rw-r--r--src/utils/lib/pager.c317
-rw-r--r--src/utils/lib/path.c1248
-rw-r--r--src/utils/lib/plymouth-ctrl.c144
-rw-r--r--src/utils/lib/procutils.c308
-rw-r--r--src/utils/lib/pty-session.c725
-rw-r--r--src/utils/lib/pwdutils.c156
-rw-r--r--src/utils/lib/randutils.c238
-rw-r--r--src/utils/lib/setproctitle.c75
-rw-r--r--src/utils/lib/sha1.c256
-rw-r--r--src/utils/lib/signames.c204
-rw-r--r--src/utils/lib/strutils.c1135
-rw-r--r--src/utils/lib/strv.c403
-rw-r--r--src/utils/lib/sysfs.c1127
-rw-r--r--src/utils/lib/timer.c95
-rw-r--r--src/utils/lib/timeutils.c611
-rw-r--r--src/utils/lib/ttyutils.c152
-rw-r--r--src/utils/libsmartcols/CMakeLists.txt22
-rw-r--r--src/utils/libsmartcols/src/buffer.c152
-rw-r--r--src/utils/libsmartcols/src/calculate.c454
-rw-r--r--src/utils/libsmartcols/src/cell.c257
-rw-r--r--src/utils/libsmartcols/src/column.c564
-rw-r--r--src/utils/libsmartcols/src/fput.c97
-rw-r--r--src/utils/libsmartcols/src/grouping.c575
-rw-r--r--src/utils/libsmartcols/src/init.c62
-rw-r--r--src/utils/libsmartcols/src/iter.c74
-rw-r--r--src/utils/libsmartcols/src/libsmartcols.h329
-rw-r--r--src/utils/libsmartcols/src/line.c540
-rw-r--r--src/utils/libsmartcols/src/print-api.c211
-rw-r--r--src/utils/libsmartcols/src/print.c1089
-rw-r--r--src/utils/libsmartcols/src/smartcolsP.h468
-rw-r--r--src/utils/libsmartcols/src/symbols.c293
-rw-r--r--src/utils/libsmartcols/src/table.c1691
-rw-r--r--src/utils/libsmartcols/src/version.c62
-rw-r--r--src/utils/libsmartcols/src/walk.c152
-rw-r--r--src/utils/sys-utils/CMakeLists.txt19
-rw-r--r--src/utils/sys-utils/xlosetup.8215
-rw-r--r--src/utils/sys-utils/xlosetup.c931
393 files changed, 86601 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..646a53f
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-src)
+
+add_subdirectory(kernel)
+add_subdirectory(utils)
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
new file mode 100644
index 0000000..dd12c80
--- /dev/null
+++ b/src/kernel/CMakeLists.txt
@@ -0,0 +1,73 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-kernel)
+
+set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+include(kernel)
+
+# set C flags for a Linux kernel module
+set(KERNEL_C_FLAGS "-DCONFIG_BLK_DEV_XLOOP_MIN_COUNT=${BLK_DEV_XLOOP_MIN_COUNT} -DXLOOP_MAJOR=${XLOOP_MAJOR} -DXLOOP_CTRL_MINOR=${XLOOP_CTRL_MINOR} -DVERSION=${VERSION}"
+ CACHE STRING "C flags to be used for building the kernel module")
+# set C flags for the debug mode of a Linux kernel module
+set(KERNEL_C_FLAGS_DEBUG "-g -DDEBUG"
+ CACHE STRING "Additional C flags to be used for building the kernel module in debug mode")
+
+# append debug C flags if debug mode is enabled
+if(CMAKE_BUILD_TYPE MATCHES Debug)
+ set(KERNEL_C_FLAGS "${KERNEL_C_FLAGS} ${KERNEL_C_FLAGS_DEBUG}")
+endif(CMAKE_BUILD_TYPE MATCHES Debug)
+
+# xloop main Linux kernel module
+set(KERNEL_MODULE_XLOOP_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_main.c)
+set(KERNEL_MODULE_XLOOP_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_main.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/uapi_xloop.h)
+add_kernel_module(xloop "${KERNEL_BUILD_DIR}"
+ "${KERNEL_INSTALL_DIR}"
+ "CONFIG_BLK_DEV_XLOOP=m"
+ "${KERNEL_MODULE_XLOOP_SOURCE_FILES}"
+ "${KERNEL_MODULE_XLOOP_HEADER_FILES}"
+ ${CMAKE_CURRENT_SOURCE_DIR}/Kbuild)
+
+# xloop_file_fmt_raw Linux kernel module
+set(KERNEL_MODULE_XLOOP_RAW_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_raw.c)
+set(KERNEL_MODULE_XLOOP_RAW_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_main.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/uapi_xloop.h)
+add_kernel_module(xloop_file_fmt_raw "${KERNEL_BUILD_DIR}"
+ "${KERNEL_INSTALL_DIR}"
+ "CONFIG_BLK_DEV_XLOOP_FILE_FMT_RAW=m"
+ "${KERNEL_MODULE_XLOOP_RAW_SOURCE_FILES}"
+ "${KERNEL_MODULE_XLOOP_RAW_HEADER_FILES}"
+ ${CMAKE_CURRENT_SOURCE_DIR}/Kbuild
+ xloop)
+
+# xloop_file_fmt_qcow Linux kernel module
+set(KERNEL_MODULE_XLOOP_QCOW_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_cache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_cluster.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_main.c)
+set(KERNEL_MODULE_XLOOP_QCOW_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_cache.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_cluster.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt_qcow_main.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_file_fmt.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/xloop_main.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/uapi_xloop.h)
+add_kernel_module(xloop_file_fmt_qcow "${KERNEL_BUILD_DIR}"
+ "${KERNEL_INSTALL_DIR}"
+ "CONFIG_BLK_DEV_XLOOP_FILE_FMT_QCOW=m"
+ "${KERNEL_MODULE_XLOOP_QCOW_SOURCE_FILES}"
+ "${KERNEL_MODULE_XLOOP_QCOW_HEADER_FILES}"
+ ${CMAKE_CURRENT_SOURCE_DIR}/Kbuild
+ xloop)
+
+if(${CMAKE_BUILD_TYPE} MATCHES Debug)
+ add_subdirectory(tests)
+endif()
+
+# install udev rules for xloop devices exposed by the xloop kernel module
+install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/udev/50-xloop.rules
+ DESTINATION /lib/udev/rules.d
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ COMPONENT main)
diff --git a/src/kernel/Kbuild b/src/kernel/Kbuild
new file mode 100644
index 0000000..0f99bb5
--- /dev/null
+++ b/src/kernel/Kbuild
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Linux kernel module xloop
+obj-$(CONFIG_BLK_DEV_XLOOP) += xloop.o
+xloop-y += xloop_main.o xloop_file_fmt.o
+
+# Linux kernel module loop_file_fmt_raw
+obj-$(CONFIG_BLK_DEV_XLOOP_FILE_FMT_RAW) += xloop_file_fmt_raw.o
+
+# Linux kernel module loop_file_fmt_qcow
+obj-$(CONFIG_BLK_DEV_XLOOP_FILE_FMT_QCOW) += xloop_file_fmt_qcow.o
+xloop_file_fmt_qcow-y += xloop_file_fmt_qcow_main.o xloop_file_fmt_qcow_cluster.o xloop_file_fmt_qcow_cache.o \ No newline at end of file
diff --git a/src/kernel/cmake/kernel.cmake b/src/kernel/cmake/kernel.cmake
new file mode 100644
index 0000000..811ce86
--- /dev/null
+++ b/src/kernel/cmake/kernel.cmake
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# CMake macros to build and install Linux kernel modules
+# Copyright (C) 2020 Manuel Bentele <development@manuel-bentele.de>
+#
+
+# macro to define kernel module targets
+macro(add_kernel_module MODULE_NAME KERNEL_BUILD_DIR KERNEL_INSTALL_DIR MODULE_MACRO MODULE_SOURCE_FILES MODULE_HEADER_FILES BUILD_SOURCE_FILE)
+ # create directory for kernel module
+ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME})
+ # copy build source file
+ get_filename_component(BUILD_SOURCE_FILENAME ${BUILD_SOURCE_FILE} NAME)
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${BUILD_SOURCE_FILENAME}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BUILD_SOURCE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}
+ DEPENDS ${BUILD_SOURCE_FILE})
+ set(BUILD_SOURCE_FILE_PREPARED ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${BUILD_SOURCE_FILENAME})
+ # copy source files
+ foreach(MODULE_SOURCE_FILE ${MODULE_SOURCE_FILES})
+ get_filename_component(MODULE_SOURCE_FILENAME ${MODULE_SOURCE_FILE} NAME)
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_SOURCE_FILENAME}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MODULE_SOURCE_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}
+ DEPENDS ${MODULE_SOURCE_FILE})
+ set(MODULE_SOURCE_FILES_PREPARED ${MODULE_SOURCE_FILES_PREPARED}
+ ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_SOURCE_FILENAME})
+ endforeach()
+ # copy header files
+ foreach(MODULE_HEADER_FILE ${MODULE_HEADER_FILES})
+ get_filename_component(MODULE_HEADER_FILENAME ${MODULE_HEADER_FILE} NAME)
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_HEADER_FILENAME}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${MODULE_HEADER_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}
+ DEPENDS ${MODULE_HEADER_FILE})
+ set(MODULE_HEADER_FILES_PREPARED ${MODULE_HEADER_FILES_PREPARED}
+ ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_HEADER_FILENAME})
+ endforeach()
+ # check if module depends on another module
+ if(NOT ${ARGV7} STREQUAL "")
+ set(MODULE_EXTRA_SYMBOLS ${CMAKE_CURRENT_BINARY_DIR}/${ARGV7}/Module.symvers)
+ endif()
+ # define build command
+ set(MODULE_BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} ${MODULE_MACRO}
+ -C ${KERNEL_BUILD_DIR}
+ M=${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME} modules
+ EXTRA_CFLAGS=${KERNEL_C_FLAGS}
+ KBUILD_EXTRA_SYMBOLS=${MODULE_EXTRA_SYMBOLS})
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_NAME}.ko
+ COMMAND ${MODULE_BUILD_COMMAND}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}
+ COMMENT "Build kernel module ${MODULE_NAME}"
+ DEPENDS ${BUILD_SOURCE_FILE_PREPARED} ${MODULE_HEADER_FILES_PREPARED} ${MODULE_SOURCE_FILES_PREPARED}
+ VERBATIM)
+ add_custom_target(${MODULE_NAME} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_NAME}.ko ${ARGV7})
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${MODULE_NAME}/${MODULE_NAME}.ko
+ DESTINATION ${KERNEL_INSTALL_DIR}
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ COMPONENT main)
+endmacro(add_kernel_module)
diff --git a/src/kernel/tests/CMakeLists.txt b/src/kernel/tests/CMakeLists.txt
new file mode 100644
index 0000000..e93ff9d
--- /dev/null
+++ b/src/kernel/tests/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(xloop-kernel-test)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/old)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+# configure configuration config.h and add it to the include directories
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_subdirectory(lib)
+add_subdirectory(testcases/kernel/syscalls/ioctl)
diff --git a/src/kernel/tests/include/config.h.in b/src/kernel/tests/include/config.h.in
new file mode 100644
index 0000000..2d59b1c
--- /dev/null
+++ b/src/kernel/tests/include/config.h.in
@@ -0,0 +1,591 @@
+/* include/config.h. Generated from config.h.in by configure. */
+/* include/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if clone() supports 7 arguments. */
+#define CLONE_SUPPORTS_7_ARGS 1
+
+/* Define to 1 if you have the <asm/ldt.h> header file. */
+#define HAVE_ASM_LDT_H 1
+
+/* Define to 1 if you have the <asm/ptrace.h> header file. */
+#define HAVE_ASM_PTRACE_H 1
+
+/* Define to 1 if you have the __atomic_* compiler builtins */
+#define HAVE_ATOMIC_MEMORY_MODEL 1
+
+/* Define to 1 if you have __builtin___clear_cache */
+#define HAVE_BUILTIN_CLEAR_CACHE 1
+
+/* Define to 1 if you have the `clnttcp_create' function. */
+/* #undef HAVE_CLNTTCP_CREATE */
+
+/* Define to 1 if you have the `clone3' function. */
+/* #undef HAVE_CLONE3 */
+
+/* Define to 1 if you have the `copy_file_range' function. */
+#define HAVE_COPY_FILE_RANGE 1
+
+/* Define to 1 if you have the `daemon' function. */
+#define HAVE_DAEMON 1
+
+/* Define to 1 if you have the declaration of `IFLA_NET_NS_PID', and to 0 if
+ you don't. */
+#define HAVE_DECL_IFLA_NET_NS_PID 1
+
+/* Define to 1 if you have the declaration of `MADV_MERGEABLE', and to 0 if
+ you don't. */
+#define HAVE_DECL_MADV_MERGEABLE 1
+
+/* Define to 1 if you have the declaration of `PR_CAPBSET_DROP', and to 0 if
+ you don't. */
+#define HAVE_DECL_PR_CAPBSET_DROP 1
+
+/* Define to 1 if you have the declaration of `PR_CAPBSET_READ', and to 0 if
+ you don't. */
+#define HAVE_DECL_PR_CAPBSET_READ 1
+
+/* Define to 1 if you have the declaration of `PTRACE_GETSIGINFO', and to 0 if
+ you don't. */
+#define HAVE_DECL_PTRACE_GETSIGINFO 1
+
+/* Define to 1 if you have the declaration of `PTRACE_O_TRACEVFORKDONE', and
+ to 0 if you don't. */
+#define HAVE_DECL_PTRACE_O_TRACEVFORKDONE 1
+
+/* Define to 1 if you have the declaration of `PTRACE_SETOPTIONS', and to 0 if
+ you don't. */
+#define HAVE_DECL_PTRACE_SETOPTIONS 1
+
+/* Define to 1 if the system has the type `enum kcmp_type'. */
+#define HAVE_ENUM_KCMP_TYPE 1
+
+/* Define to 1 if you have the `epoll_pwait' function. */
+#define HAVE_EPOLL_PWAIT 1
+
+/* Define to 1 if you have the `execveat' function. */
+/* #undef HAVE_EXECVEAT */
+
+/* Define to 1 if you have the `fallocate' function. */
+#define HAVE_FALLOCATE 1
+
+/* Define to 1 if you have the `fchownat' function. */
+#define HAVE_FCHOWNAT 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `fsconfig' function. */
+/* #undef HAVE_FSCONFIG */
+
+/* Define to 1 if you have the `fsmount' function. */
+/* #undef HAVE_FSMOUNT */
+
+/* Define to 1 if you have the `fsopen' function. */
+/* #undef HAVE_FSOPEN */
+
+/* Define to 1 if you have the `fspick' function. */
+/* #undef HAVE_FSPICK */
+
+/* Define to 1 if you have the `fstatat' function. */
+#define HAVE_FSTATAT 1
+
+/* Define to 1 if you have the <fts.h> header file. */
+#define HAVE_FTS_H 1
+
+/* Define to 1 if you have the `getauxval' function. */
+#define HAVE_GETAUXVAL 1
+
+/* Define to 1 if you have the `getdents' function. */
+/* #undef HAVE_GETDENTS */
+
+/* Define to 1 if you have the `getdents64' function. */
+#define HAVE_GETDENTS64 1
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `io_pgetevents' function. */
+/* #undef HAVE_IO_PGETEVENTS */
+
+/* Define to 1 if you have `io_set_eventfd' function. */
+#define HAVE_IO_SET_EVENTFD 1
+
+/* Define to 1 if you have the `io_uring_enter' function. */
+/* #undef HAVE_IO_URING_ENTER */
+
+/* Define to 1 if you have the `io_uring_register' function. */
+/* #undef HAVE_IO_URING_REGISTER */
+
+/* Define to 1 if you have the `io_uring_setup' function. */
+/* #undef HAVE_IO_URING_SETUP */
+
+/* Define to 1 if you have the `kcmp' function. */
+/* #undef HAVE_KCMP */
+
+/* Define to 1 if you have the <keyutils.h> header file. */
+#define HAVE_KEYUTILS_H 1
+
+/* Define to 1 if you have libacl and it's headers installed */
+#define HAVE_LIBACL 1
+
+/* Define to 1 if you have libaio and it's headers installed. */
+#define HAVE_LIBAIO 1
+
+/* Define to 1 if you have the <libaio.h> header file. */
+#define HAVE_LIBAIO_H 1
+
+/* Define to 1 if you have libcap-2 installed. */
+#define HAVE_LIBCAP 1
+
+/* Define whether libcrypto and openssl headers are installed */
+#define HAVE_LIBCRYPTO 1
+
+/* Define to 1 if you have libkeyutils installed. */
+#define HAVE_LIBKEYUTILS 1
+
+/* Define to 1 if you have libmnl library and headers */
+#define HAVE_LIBMNL 1
+
+/* Define to 1 if you have both SELinux libraries and headers. */
+/* #undef HAVE_LIBSELINUX_DEVEL */
+
+/* Define to 1 if you have the <linux/can.h> header file. */
+#define HAVE_LINUX_CAN_H 1
+
+/* Define to 1 if you have the <linux/cgroupstats.h> header file. */
+#define HAVE_LINUX_CGROUPSTATS_H 1
+
+/* Define to 1 if you have the <linux/cryptouser.h> header file. */
+#define HAVE_LINUX_CRYPTOUSER_H 1
+
+/* Define to 1 if you have the <linux/dccp.h> header file. */
+#define HAVE_LINUX_DCCP_H 1
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+#define HAVE_LINUX_FS_H 1
+
+/* Define to 1 if you have the <linux/genetlink.h> header file. */
+#define HAVE_LINUX_GENETLINK_H 1
+
+/* Define to 1 if you have the <linux/if_alg.h> header file. */
+#define HAVE_LINUX_IF_ALG_H 1
+
+/* Define to 1 if you have the <linux/if_ether.h> header file. */
+#define HAVE_LINUX_IF_ETHER_H 1
+
+/* Define to 1 if you have the <linux/if_packet.h> header file. */
+#define HAVE_LINUX_IF_PACKET_H 1
+
+/* Define to 1 if you have the <linux/keyctl.h> header file. */
+#define HAVE_LINUX_KEYCTL_H 1
+
+/* Define to 1 if you have the <linux/mempolicy.h> header file. */
+#define HAVE_LINUX_MEMPOLICY_H 1
+
+/* Define to 1 if you have the <linux/module.h> header file. */
+#define HAVE_LINUX_MODULE_H 1
+
+/* Define to 1 if you have the <linux/netlink.h> header file. */
+#define HAVE_LINUX_NETLINK_H 1
+
+/* Define to 1 if you have the <linux/ptrace.h> header file. */
+#define HAVE_LINUX_PTRACE_H 1
+
+/* Define to 1 if having a valid linux/random.h */
+#define HAVE_LINUX_RANDOM_H 1
+
+/* Define to 1 if you have the <linux/seccomp.h> header file. */
+#define HAVE_LINUX_SECCOMP_H 1
+
+/* Define to 1 if you have the <linux/securebits.h> header file. */
+#define HAVE_LINUX_SECUREBITS_H 1
+
+/* Define to 1 if you have the <linux/signalfd.h> header file. */
+#define HAVE_LINUX_SIGNALFD_H 1
+
+/* Define to 1 if you have the <linux/taskstats.h> header file. */
+#define HAVE_LINUX_TASKSTATS_H 1
+
+/* Define to 1 if you have the <linux/tty.h> header file. */
+#define HAVE_LINUX_TTY_H 1
+
+/* Define to 1 if you have the <linux/types.h> header file. */
+#define HAVE_LINUX_TYPES_H 1
+
+/* Define to 1 if you have the <linux/userfaultfd.h> header file. */
+#define HAVE_LINUX_USERFAULTFD_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkdirat' function. */
+#define HAVE_MKDIRAT 1
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#define HAVE_MKDTEMP 1
+
+/* Define to 1 if you have the `mknodat' function. */
+#define HAVE_MKNODAT 1
+
+/* Define to 1 if you have the `modify_ldt' function. */
+#define HAVE_MODIFY_LDT 1
+
+/* Define to 1 if you have the `move_mount' function. */
+/* #undef HAVE_MOVE_MOUNT */
+
+/* Define to 1 if you have MREMAP_FIXED in <sys/mman.h>. */
+#define HAVE_MREMAP_FIXED 1
+
+/* Define to 1 if you have the `name_to_handle_at' function. */
+#define HAVE_NAME_TO_HANDLE_AT 1
+
+/* Define to 1 if you have the <netinet/sctp.h> header file. */
+/* #undef HAVE_NETINET_SCTP_H */
+
+/* Define to 1 if you have newer libcap-2 installed. */
+#define HAVE_NEWER_LIBCAP 1
+
+/* Define to 1 if you have the <numaif.h> header file. */
+#define HAVE_NUMAIF_H 1
+
+/* Define to 1 if you have the <numa.h> header file. */
+#define HAVE_NUMA_H 1
+
+/* Define to 1 if you have libnuma and it's headers version >= 2 installed. */
+#define HAVE_NUMA_V2 1
+
+/* Define to 1 if you have the `openat' function. */
+#define HAVE_OPENAT 1
+
+/* Define to 1 if you have the `openat2' function. */
+/* #undef HAVE_OPENAT2 */
+
+/* Define to 1 if you have the <openssl/sha.h> header file. */
+#define HAVE_OPENSSL_SHA_H 1
+
+/* Define to 1 if you have the `open_tree' function. */
+/* #undef HAVE_OPEN_TREE */
+
+/* Define to 1 if you have struct perf_event_attr */
+#define HAVE_PERF_EVENT_ATTR 1
+
+/* Define to 1 if you have the `pidfd_open' function. */
+/* #undef HAVE_PIDFD_OPEN */
+
+/* Define to 1 if you have the `pidfd_send_signal' function. */
+/* #undef HAVE_PIDFD_SEND_SIGNAL */
+
+/* Define to 1 if you have the `pkey_mprotect' function. */
+#define HAVE_PKEY_MPROTECT 1
+
+/* Define to 1 if you have the `preadv' function. */
+#define HAVE_PREADV 1
+
+/* Define to 1 if you have the `preadv2' function. */
+#define HAVE_PREADV2 1
+
+/* Define to 1 if you have the `profil' function. */
+#define HAVE_PROFIL 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#define HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the `pwritev' function. */
+#define HAVE_PWRITEV 1
+
+/* Define to 1 if you have the `pwritev2' function. */
+#define HAVE_PWRITEV2 1
+
+/* Define to 1 if you have the `readlinkat' function. */
+#define HAVE_READLINKAT 1
+
+/* Define to 1 if you have the `recvmmsg' function. */
+#define HAVE_RECVMMSG 1
+
+/* Define to 1 if you have the `renameat' function. */
+#define HAVE_RENAMEAT 1
+
+/* Define to 1 if you have the `renameat2' function. */
+#define HAVE_RENAMEAT2 1
+
+/* Define to 1 if you have the `sched_getcpu' function. */
+#define HAVE_SCHED_GETCPU 1
+
+/* Define to 1 if you have the <selinux/selinux.h> header file. */
+/* #undef HAVE_SELINUX_SELINUX_H */
+
+/* Define to 1 if you have the `sendmmsg' function. */
+#define HAVE_SENDMMSG 1
+
+/* Define to 1 if you have the `setns' function. */
+#define HAVE_SETNS 1
+
+/* Define to 1 if you have the `signalfd' function. */
+#define HAVE_SIGNALFD 1
+
+/* Define to 1 if you have the `sigpending' function. */
+#define HAVE_SIGPENDING 1
+
+/* Define to 1 if you have the `splice' function. */
+#define HAVE_SPLICE 1
+
+/* Define to 1 if you have the `statx' function. */
+#define HAVE_STATX 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `stime' function. */
+/* #undef HAVE_STIME */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if the system has the type `struct acct_v3'. */
+#define HAVE_STRUCT_ACCT_V3 1
+
+/* Define to 1 if the system has the type `struct af_alg_iv'. */
+#define HAVE_STRUCT_AF_ALG_IV 1
+
+/* Define to 1 if the system has the type `struct fanotify_event_info_fid'. */
+#define HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID 1
+
+/* Define to 1 if `fsid.__val' is a member of `struct
+ fanotify_event_info_fid'. */
+/* #undef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */
+
+/* Define to 1 if the system has the type `struct fanotify_event_info_header'.
+ */
+#define HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER 1
+
+/* Define to 1 if the system has the type `struct file_dedupe_range'. */
+#define HAVE_STRUCT_FILE_DEDUPE_RANGE 1
+
+/* Define to 1 if the system has the type `struct fs_quota_statv'. */
+#define HAVE_STRUCT_FS_QUOTA_STATV 1
+
+/* Define to 1 if you have struct f_owner_ex */
+#define HAVE_STRUCT_F_OWNER_EX 1
+
+/* Define to 1 if the system has the type `struct if_nextdqblk'. */
+#define HAVE_STRUCT_IF_NEXTDQBLK 1
+
+/* Define to 1 if the system has the type `struct iovec'. */
+#define HAVE_STRUCT_IOVEC 1
+
+/* Define to 1 if the system has the type `struct ipc64_perm'. */
+/* #undef HAVE_STRUCT_IPC64_PERM */
+
+/* Define to 1 if the system has the type `struct loop_config'. */
+#define HAVE_STRUCT_LOOP_CONFIG 1
+
+/* Define to 1 if the system has the type `struct mmsghdr'. */
+#define HAVE_STRUCT_MMSGHDR 1
+
+/* Define to 1 if the system has the type `struct modify_ldt_ldt_s'. */
+/* #undef HAVE_STRUCT_MODIFY_LDT_LDT_S */
+
+/* Define to 1 if the system has the type `struct msqid64_ds'. */
+/* #undef HAVE_STRUCT_MSQID64_DS */
+
+/* Define to 1 if `aux_head' is a member of `struct perf_event_mmap_page'. */
+#define HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_AUX_HEAD 1
+
+/* Define to 1 if the system has the type `struct ptrace_peeksiginfo_args'. */
+/* #undef HAVE_STRUCT_PTRACE_PEEKSIGINFO_ARGS */
+
+/* Define to 1 if the system has the type `struct pt_regs'. */
+#define HAVE_STRUCT_PT_REGS 1
+
+/* Define to 1 if the system has the type `struct rlimit64'. */
+#define HAVE_STRUCT_RLIMIT64 1
+
+/* Define to 1 if the system has the type `struct semid64_ds'. */
+/* #undef HAVE_STRUCT_SEMID64_DS */
+
+/* Define to 1 if the system has the type `struct shmid64_ds'. */
+/* #undef HAVE_STRUCT_SHMID64_DS */
+
+/* Define to 1 if `sa_sigaction' is a member of `struct sigaction'. */
+#define HAVE_STRUCT_SIGACTION_SA_SIGACTION 1
+
+/* Define to 1 if `ssi_signo' is a member of `struct signalfd_siginfo'. */
+#define HAVE_STRUCT_SIGNALFD_SIGINFO_SSI_SIGNO 1
+
+/* Define to 1 if the system has the type `struct sockaddr_alg'. */
+#define HAVE_STRUCT_SOCKADDR_ALG 1
+
+/* Define to 1 if the system has the type `struct statx'. */
+#define HAVE_STRUCT_STATX 1
+
+/* Define to 1 if the system has the type `struct statx_timestamp'. */
+#define HAVE_STRUCT_STATX_TIMESTAMP 1
+
+/* Define to 1 if `freepages_count' is a member of `struct taskstats'. */
+#define HAVE_STRUCT_TASKSTATS_FREEPAGES_COUNT 1
+
+/* Define to 1 if `nvcsw' is a member of `struct taskstats'. */
+#define HAVE_STRUCT_TASKSTATS_NVCSW 1
+
+/* Define to 1 if `read_bytes' is a member of `struct taskstats'. */
+#define HAVE_STRUCT_TASKSTATS_READ_BYTES 1
+
+/* Define to 1 if the system has the type `struct termio'. */
+#define HAVE_STRUCT_TERMIO 1
+
+/* Define to 1 if the system has the type `struct tpacket_req3'. */
+#define HAVE_STRUCT_TPACKET_REQ3 1
+
+/* Define to 1 if the system has the type `struct user_desc'. */
+#define HAVE_STRUCT_USER_DESC 1
+
+/* Define to 1 if the system has the type `struct user_regs_struct'. */
+/* #undef HAVE_STRUCT_USER_REGS_STRUCT */
+
+/* Define to 1 if `domainname' is a member of `struct utsname'. */
+#define HAVE_STRUCT_UTSNAME_DOMAINNAME 1
+
+/* Define to 1 if the system has the type `struct xt_entry_match'. */
+#define HAVE_STRUCT_XT_ENTRY_MATCH 1
+
+/* Define to 1 if the system has the type `struct xt_entry_target'. */
+#define HAVE_STRUCT_XT_ENTRY_TARGET 1
+
+/* Define to 1 if you have the `syncfs' function. */
+#define HAVE_SYNCFS 1
+
+/* Define to 1 if you have __sync_add_and_fetch */
+#define HAVE_SYNC_ADD_AND_FETCH 1
+
+/* Define to 1 if you have the `sync_file_range' function. */
+#define HAVE_SYNC_FILE_RANGE 1
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+#define HAVE_SYS_ACL_H 1
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#define HAVE_SYS_CAPABILITY_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/fanotify.h> header file. */
+#define HAVE_SYS_FANOTIFY_H 1
+
+/* Define to 1 if you have the <sys/inotify.h> header file. */
+#define HAVE_SYS_INOTIFY_H 1
+
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#define HAVE_SYS_PRCTL_H 1
+
+/* Define to 1 if you have the <sys/ptrace.h> header file. */
+#define HAVE_SYS_PTRACE_H 1
+
+/* Define to 1 if you have the <sys/reg.h> header file. */
+#define HAVE_SYS_REG_H 1
+
+/* Define to 1 if you have the <sys/shm.h> header file. */
+#define HAVE_SYS_SHM_H 1
+
+/* Define to 1 if you have the <sys/signalfd.h> header file. */
+#define HAVE_SYS_SIGNALFD_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/timerfd.h> header file. */
+#define HAVE_SYS_TIMERFD_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ustat.h> header file. */
+/* #undef HAVE_SYS_USTAT_H */
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H 1
+
+/* Define to 1 if you have the <sys/xattr.h> header file. */
+#define HAVE_SYS_XATTR_H 1
+
+/* Define to 1 if you have the `tee' function. */
+#define HAVE_TEE 1
+
+/* Define to 1 if you have the `timerfd_create' function. */
+#define HAVE_TIMERFD_CREATE 1
+
+/* Define to 1 if you have the `timerfd_gettime' function. */
+#define HAVE_TIMERFD_GETTIME 1
+
+/* Define to 1 if you have the `timerfd_settime' function. */
+#define HAVE_TIMERFD_SETTIME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unshare' function. */
+#define HAVE_UNSHARE 1
+
+/* Define to 1 if you have the `ustat' function. */
+/* #undef HAVE_USTAT */
+
+/* Define to 1 if you have utimensat(2) */
+#define HAVE_UTIMENSAT 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the `vmsplice' function. */
+#define HAVE_VMSPLICE 1
+
+/* Define to 1 if you have the `xdr_char' function. */
+/* #undef HAVE_XDR_CHAR */
+
+/* Define to 1 if you have the <xfs/xqm.h> header file. */
+#define HAVE_XFS_XQM_H 1
+
+/* Error message when no NUMA support */
+#define NUMA_ERROR_MSG "test requires libnuma >= 2 and it's development packages"
+
+/* Name of package */
+#define PACKAGE "ltp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "ltp@lists.linux.it"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "ltp"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "ltp @VERSION@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "ltp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@VERSION@"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Target is running Linux w/out an MMU */
+/* #undef UCLINUX */
+
+/* Version number of package */
+#define VERSION "@VERSION@"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#define YYTEXT_POINTER 1
diff --git a/src/kernel/tests/include/ipcmsg.h b/src/kernel/tests/include/ipcmsg.h
new file mode 100644
index 0000000..d89894b
--- /dev/null
+++ b/src/kernel/tests/include/ipcmsg.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * ipcmsg.h - common definitions for the IPC message tests.
+ */
+
+#ifndef __IPCMSG_H
+#define __IPCMSG_H 1
+
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/types.h>
+
+#include "test.h"
+
+void cleanup(void);
+void setup(void);
+
+#define MSG_RD 0400 /* read permission for the queue */
+#define MSG_WR 0200 /* write permission for the queue */
+#define MSG_RW MSG_RD | MSG_WR
+
+#define MSGSIZE 1024 /* a resonable size for a message */
+#define MSGTYPE 1 /* a type ID for a message */
+
+#define NR_MSGQUEUES 16 /* MSGMNI as defined in linux/msg.h */
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+typedef struct mbuf { /* a generic message structure */
+ long mtype;
+ char mtext[MSGSIZE + 1]; /* add 1 here so the message can be 1024 */
+} MSGBUF; /* characters long with a '\0' termination */
+
+#ifdef LIBIPC
+key_t msgkey; /* the ftok() generated message key */
+#else
+extern key_t msgkey; /* the ftok() generated message key */
+#endif
+
+void init_buf(MSGBUF *, int, int);
+void rm_queue(int);
+
+key_t getipckey();
+int getuserid(char *);
+
+int get_max_msgqueues(void);
+int get_used_msgqueues(void);
+
+#endif /* ipcmsg.h */
diff --git a/src/kernel/tests/include/ipcsem.h b/src/kernel/tests/include/ipcsem.h
new file mode 100644
index 0000000..6a37672
--- /dev/null
+++ b/src/kernel/tests/include/ipcsem.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * ipcsem.h - common definitions for the IPC semaphore tests
+ */
+
+#ifndef __IPCSEM_H
+#define __IPCSEM_H
+
+#include <errno.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+#include "test.h"
+#include "lapi/semun.h"
+
+void cleanup(void);
+void setup(void);
+
+#define SEM_RD 0400
+#define SEM_ALT 0200
+#define SEM_RA SEM_RD | SEM_ALT
+
+#define PSEMS 10 /* a reasonable value for the number of */
+ /* "primitive semaphores" per ID */
+
+#ifdef LIBIPC
+key_t semkey; /* an IPC key generated by ftok() */
+#else
+extern key_t semkey; /* an IPC key generated by ftok() */
+#endif
+
+void rm_sema(int sem_id);
+
+int getipckey();
+int getuserid(char *);
+
+#endif /* ipcsem.h */
diff --git a/src/kernel/tests/include/ipcshm.h b/src/kernel/tests/include/ipcshm.h
new file mode 100644
index 0000000..08307d4
--- /dev/null
+++ b/src/kernel/tests/include/ipcshm.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * ipcshm.h - common definitions for the IPC shared memory tests
+ */
+
+#ifndef __IPCSHM_H
+#define __IPCSHM_H
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "test.h"
+
+void cleanup(void);
+void setup(void);
+
+#define SHM_RD 0400
+#define SHM_WR 0200
+#define SHM_RW SHM_RD | SHM_WR
+
+#define SHM_SIZE 2048 /* a resonable size for a memory segment */
+#define INT_SIZE 4 /* instead of sizeof(int) */
+
+#define MODE_MASK 0x01FF /* to get the lower nine permission bits */
+ /* from shmid_ds.ipc_perm.mode */
+
+key_t shmkey; /* an IPC key generated by ftok() */
+
+void rm_shm(int shm_id);
+
+int getipckey();
+int getuserid(char*);
+
+#endif /* ipcshm.h */
diff --git a/src/kernel/tests/include/lapi/abisize.h b/src/kernel/tests/include/lapi/abisize.h
new file mode 100644
index 0000000..9e6622c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/abisize.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014-2019 Linux Test Project
+ * Cyril Hrubis <chrubis@suse.cz>
+ * Petr Vorel <petr.vorel@gmail.com>
+ */
+
+#ifndef ABISIZE_H__
+#define ABISIZE_H__
+
+/* __WORDSIZE replacement */
+#if defined(__LP64__) || defined(_LP64)
+# define TST_ABI64
+# define TST_ABI 64
+#else
+# define TST_ABI32
+# define TST_ABI 32
+#endif
+
+/*
+ * Determines if we have to split up 64 bit arguments or not
+ *
+ * Deals with 32bit ABIs that have 64bit syscalls
+ */
+#define LTP_USE_64_ABI \
+ (defined(__mips__) && _MIPS_SIM == _ABIN32) || \
+ (defined(__x86_64__) && defined(__ILP32__)) || \
+ (defined(__aarch64__) && defined(__ILP32__)) || \
+ defined(TST_ABI64)
+
+#endif /* ABISIZE_H__ */
diff --git a/src/kernel/tests/include/lapi/acct.h b/src/kernel/tests/include/lapi/acct.h
new file mode 100644
index 0000000..c81b78b
--- /dev/null
+++ b/src/kernel/tests/include/lapi/acct.h
@@ -0,0 +1,74 @@
+//SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef LAPI_ACCT_H
+#define LAPI_ACCT_H
+
+#include <sys/types.h>
+#include "config.h"
+
+#ifdef HAVE_STRUCT_ACCT_V3
+#include <sys/acct.h>
+#else
+
+#define ACCT_COMM 16
+
+typedef uint16_t comp_t;
+
+/* Fallback structures to parse the process accounting file */
+struct acct {
+ char ac_flag;
+ uint16_t ac_uid;
+ uint16_t ac_gid;
+ uint16_t ac_tty;
+ uint32_t ac_btime;
+ comp_t ac_utime;
+ comp_t ac_stime;
+ comp_t ac_etime;
+ comp_t ac_mem;
+ comp_t ac_io;
+ comp_t ac_rw;
+ comp_t ac_minflt;
+ comp_t ac_majflt;
+ comp_t ac_swaps;
+ uint32_t ac_exitcode;
+ char ac_comm[ACCT_COMM+1];
+ char ac_pad[10];
+};
+
+struct acct_v3 {
+ char ac_flag;
+ char ac_version;
+ uint16_t ac_tty;
+ uint32_t ac_exitcode;
+ uint32_t ac_uid;
+ uint32_t ac_gid;
+ uint32_t ac_pid;
+ uint32_t ac_ppid;
+ uint32_t ac_btime;
+ float ac_etime;
+ comp_t ac_utime;
+ comp_t ac_stime;
+ comp_t ac_mem;
+ comp_t ac_io;
+ comp_t ac_rw;
+ comp_t ac_minflt;
+ comp_t ac_majflt;
+ comp_t ac_swaps;
+ char ac_comm[ACCT_COMM];
+};
+
+/* Possible values for the ac_flag member */
+enum {
+ AFORK = 0x01,
+ ASU = 0x02,
+ ACORE = 0x08,
+ AXSIG = 0x10
+};
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define ACCT_BYTEORDER 0x80
+# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define ACCT_BYTEORDER 0x00
+# endif
+#endif /* HAVE_STRUCT_ACCT_V3 */
+
+#endif /* LAPI_ACCT_H */
diff --git a/src/kernel/tests/include/lapi/bpf.h b/src/kernel/tests/include/lapi/bpf.h
new file mode 100644
index 0000000..f27a921
--- /dev/null
+++ b/src/kernel/tests/include/lapi/bpf.h
@@ -0,0 +1,591 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Essential Extended Berkeley Packet Filter (eBPF) headers
+ *
+ * Mostly copied/adapted from linux/bpf.h and libbpf so that we can perform
+ * some eBPF testing without any external dependencies.
+ */
+
+#ifndef BPF_H
+# define BPF_H
+
+#include <stdint.h>
+
+#include "lapi/syscalls.h"
+
+/* Start copy from linux/bpf_(common).h */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+
+#define BPF_JNE 0x50 /* jump != */
+
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00 /* 32-bit */
+#define BPF_DW 0x18 /* double word (64-bit) */
+
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_MEM 0x60
+
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+
+#define BPF_JEQ 0x10
+
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+#define BPF_ALU64 0x07 /* alu mode in double word width */
+#define BPF_MOV 0xb0 /* mov reg to reg */
+#define BPF_CALL 0x80 /* function call */
+#define BPF_EXIT 0x90 /* function return */
+
+/* Register numbers */
+enum {
+ BPF_REG_0 = 0,
+ BPF_REG_1,
+ BPF_REG_2,
+ BPF_REG_3,
+ BPF_REG_4,
+ BPF_REG_5,
+ BPF_REG_6,
+ BPF_REG_7,
+ BPF_REG_8,
+ BPF_REG_9,
+ BPF_REG_10,
+ MAX_BPF_REG,
+};
+
+struct bpf_insn {
+ uint8_t code; /* opcode */
+ uint8_t dst_reg:4; /* dest register */
+ uint8_t src_reg:4; /* source register */
+ int16_t off; /* signed offset */
+ int32_t imm; /* signed immediate constant */
+};
+
+enum bpf_cmd {
+ BPF_MAP_CREATE,
+ BPF_MAP_LOOKUP_ELEM,
+ BPF_MAP_UPDATE_ELEM,
+ BPF_MAP_DELETE_ELEM,
+ BPF_MAP_GET_NEXT_KEY,
+ BPF_PROG_LOAD,
+ BPF_OBJ_PIN,
+ BPF_OBJ_GET,
+ BPF_PROG_ATTACH,
+ BPF_PROG_DETACH,
+ BPF_PROG_TEST_RUN,
+ BPF_PROG_GET_NEXT_ID,
+ BPF_MAP_GET_NEXT_ID,
+ BPF_PROG_GET_FD_BY_ID,
+ BPF_MAP_GET_FD_BY_ID,
+ BPF_OBJ_GET_INFO_BY_FD,
+ BPF_PROG_QUERY,
+ BPF_RAW_TRACEPOINT_OPEN,
+ BPF_BTF_LOAD,
+ BPF_BTF_GET_FD_BY_ID,
+ BPF_TASK_FD_QUERY,
+ BPF_MAP_LOOKUP_AND_DELETE_ELEM,
+ BPF_MAP_FREEZE,
+};
+
+enum bpf_map_type {
+ BPF_MAP_TYPE_UNSPEC,
+ BPF_MAP_TYPE_HASH,
+ BPF_MAP_TYPE_ARRAY,
+ BPF_MAP_TYPE_PROG_ARRAY,
+ BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+ BPF_MAP_TYPE_PERCPU_HASH,
+ BPF_MAP_TYPE_PERCPU_ARRAY,
+ BPF_MAP_TYPE_STACK_TRACE,
+ BPF_MAP_TYPE_CGROUP_ARRAY,
+ BPF_MAP_TYPE_LRU_HASH,
+ BPF_MAP_TYPE_LRU_PERCPU_HASH,
+ BPF_MAP_TYPE_LPM_TRIE,
+ BPF_MAP_TYPE_ARRAY_OF_MAPS,
+ BPF_MAP_TYPE_HASH_OF_MAPS,
+ BPF_MAP_TYPE_DEVMAP,
+ BPF_MAP_TYPE_SOCKMAP,
+ BPF_MAP_TYPE_CPUMAP,
+ BPF_MAP_TYPE_XSKMAP,
+ BPF_MAP_TYPE_SOCKHASH,
+ BPF_MAP_TYPE_CGROUP_STORAGE,
+ BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
+ BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
+ BPF_MAP_TYPE_QUEUE,
+ BPF_MAP_TYPE_STACK,
+ BPF_MAP_TYPE_SK_STORAGE,
+};
+
+enum bpf_prog_type {
+ BPF_PROG_TYPE_UNSPEC,
+ BPF_PROG_TYPE_SOCKET_FILTER,
+ BPF_PROG_TYPE_KPROBE,
+ BPF_PROG_TYPE_SCHED_CLS,
+ BPF_PROG_TYPE_SCHED_ACT,
+ BPF_PROG_TYPE_TRACEPOINT,
+ BPF_PROG_TYPE_XDP,
+ BPF_PROG_TYPE_PERF_EVENT,
+ BPF_PROG_TYPE_CGROUP_SKB,
+ BPF_PROG_TYPE_CGROUP_SOCK,
+ BPF_PROG_TYPE_LWT_IN,
+ BPF_PROG_TYPE_LWT_OUT,
+ BPF_PROG_TYPE_LWT_XMIT,
+ BPF_PROG_TYPE_SOCK_OPS,
+ BPF_PROG_TYPE_SK_SKB,
+ BPF_PROG_TYPE_CGROUP_DEVICE,
+ BPF_PROG_TYPE_SK_MSG,
+ BPF_PROG_TYPE_RAW_TRACEPOINT,
+ BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
+ BPF_PROG_TYPE_LWT_SEG6LOCAL,
+ BPF_PROG_TYPE_LIRC_MODE2,
+ BPF_PROG_TYPE_SK_REUSEPORT,
+ BPF_PROG_TYPE_FLOW_DISSECTOR,
+ BPF_PROG_TYPE_CGROUP_SYSCTL,
+ BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
+ BPF_PROG_TYPE_CGROUP_SOCKOPT,
+};
+
+#define BPF_PSEUDO_MAP_FD 1
+
+#define BPF_OBJ_NAME_LEN 16U
+
+#define BPF_ANY 0 /* create new element or update existing */
+#define BPF_NOEXIST 1 /* create new element if it didn't exist */
+#define BPF_EXIST 2 /* update existing element */
+#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */
+
+#define aligned_uint64_t uint64_t __attribute__((aligned(8)))
+
+union bpf_attr {
+ struct { /* anonymous struct used by BPF_MAP_CREATE command */
+ uint32_t map_type; /* one of enum bpf_map_type */
+ uint32_t key_size; /* size of key in bytes */
+ uint32_t value_size; /* size of value in bytes */
+ uint32_t max_entries; /* max number of entries in a map */
+ uint32_t map_flags; /* BPF_MAP_CREATE related
+ * flags defined above.
+ */
+ uint32_t inner_map_fd; /* fd pointing to the inner map */
+ uint32_t numa_node; /* numa node (effective only if
+ * BPF_F_NUMA_NODE is set).
+ */
+ char map_name[BPF_OBJ_NAME_LEN];
+ uint32_t map_ifindex; /* ifindex of netdev to create on */
+ uint32_t btf_fd; /* fd pointing to a BTF type data */
+ uint32_t btf_key_type_id; /* BTF type_id of the key */
+ uint32_t btf_value_type_id; /* BTF type_id of the value */
+ };
+
+ struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
+ uint32_t map_fd;
+ aligned_uint64_t key;
+ union {
+ aligned_uint64_t value;
+ aligned_uint64_t next_key;
+ };
+ uint64_t flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_LOAD command */
+ uint32_t prog_type; /* one of enum bpf_prog_type */
+ uint32_t insn_cnt;
+ aligned_uint64_t insns;
+ aligned_uint64_t license;
+ uint32_t log_level; /* verbosity level of verifier */
+ uint32_t log_size; /* size of user buffer */
+ aligned_uint64_t log_buf; /* user supplied buffer */
+ uint32_t kern_version; /* not used */
+ uint32_t prog_flags;
+ char prog_name[BPF_OBJ_NAME_LEN];
+ uint32_t prog_ifindex; /* ifindex of netdev to prep for */
+ /* For some prog types expected attach type must be known at
+ * load time to verify attach type specific parts of prog
+ * (context accesses, allowed helpers, etc).
+ */
+ uint32_t expected_attach_type;
+ uint32_t prog_btf_fd; /* fd pointing to BTF type data */
+ uint32_t func_info_rec_size; /* userspace bpf_func_info size */
+ aligned_uint64_t func_info; /* func info */
+ uint32_t func_info_cnt; /* number of bpf_func_info records */
+ uint32_t line_info_rec_size; /* userspace bpf_line_info size */
+ aligned_uint64_t line_info; /* line info */
+ uint32_t line_info_cnt; /* number of bpf_line_info records */
+ };
+
+ struct { /* anonymous struct used by BPF_OBJ_* commands */
+ aligned_uint64_t pathname;
+ uint32_t bpf_fd;
+ uint32_t file_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
+ uint32_t target_fd; /* container object to attach to */
+ uint32_t attach_bpf_fd; /* eBPF program to attach */
+ uint32_t attach_type;
+ uint32_t attach_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
+ uint32_t prog_fd;
+ uint32_t retval;
+ uint32_t data_size_in; /* input: len of data_in */
+ uint32_t data_size_out; /* input/output: len of data_out
+ * returns ENOSPC if data_out
+ * is too small.
+ */
+ aligned_uint64_t data_in;
+ aligned_uint64_t data_out;
+ uint32_t repeat;
+ uint32_t duration;
+ uint32_t ctx_size_in; /* input: len of ctx_in */
+ uint32_t ctx_size_out; /* input/output: len of ctx_out
+ * returns ENOSPC if ctx_out
+ * is too small.
+ */
+ aligned_uint64_t ctx_in;
+ aligned_uint64_t ctx_out;
+ } test;
+
+ struct { /* anonymous struct used by BPF_*_GET_*_ID */
+ union {
+ uint32_t start_id;
+ uint32_t prog_id;
+ uint32_t map_id;
+ uint32_t btf_id;
+ };
+ uint32_t next_id;
+ uint32_t open_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
+ uint32_t bpf_fd;
+ uint32_t info_len;
+ aligned_uint64_t info;
+ } info;
+
+ struct { /* anonymous struct used by BPF_PROG_QUERY command */
+ uint32_t target_fd; /* container object to query */
+ uint32_t attach_type;
+ uint32_t query_flags;
+ uint32_t attach_flags;
+ aligned_uint64_t prog_ids;
+ uint32_t prog_cnt;
+ } query;
+
+ struct {
+ uint64_t name;
+ uint32_t prog_fd;
+ } raw_tracepoint;
+
+ struct { /* anonymous struct for BPF_BTF_LOAD */
+ aligned_uint64_t btf;
+ aligned_uint64_t btf_log_buf;
+ uint32_t btf_size;
+ uint32_t btf_log_size;
+ uint32_t btf_log_level;
+ };
+
+ struct {
+ uint32_t pid; /* input: pid */
+ uint32_t fd; /* input: fd */
+ uint32_t flags; /* input: flags */
+ uint32_t buf_len; /* input/output: buf len */
+ aligned_uint64_t buf; /* input/output:
+ * tp_name for tracepoint
+ * symbol for kprobe
+ * filename for uprobe
+ */
+ uint32_t prog_id; /* output: prod_id */
+ uint32_t fd_type; /* output: BPF_FD_TYPE_* */
+ uint64_t probe_offset; /* output: probe_offset */
+ uint64_t probe_addr; /* output: probe_addr */
+ } task_fd_query;
+} __attribute__((aligned(8)));
+
+#define __BPF_FUNC_MAPPER(FN) \
+ FN(unspec), \
+ FN(map_lookup_elem), \
+ FN(map_update_elem), \
+ FN(map_delete_elem), \
+ FN(probe_read), \
+ FN(ktime_get_ns), \
+ FN(trace_printk), \
+ FN(get_prandom_u32), \
+ FN(get_smp_processor_id), \
+ FN(skb_store_bytes), \
+ FN(l3_csum_replace), \
+ FN(l4_csum_replace), \
+ FN(tail_call), \
+ FN(clone_redirect), \
+ FN(get_current_pid_tgid), \
+ FN(get_current_uid_gid), \
+ FN(get_current_comm), \
+ FN(get_cgroup_classid), \
+ FN(skb_vlan_push), \
+ FN(skb_vlan_pop), \
+ FN(skb_get_tunnel_key), \
+ FN(skb_set_tunnel_key), \
+ FN(perf_event_read), \
+ FN(redirect), \
+ FN(get_route_realm), \
+ FN(perf_event_output), \
+ FN(skb_load_bytes), \
+ FN(get_stackid), \
+ FN(csum_diff), \
+ FN(skb_get_tunnel_opt), \
+ FN(skb_set_tunnel_opt), \
+ FN(skb_change_proto), \
+ FN(skb_change_type), \
+ FN(skb_under_cgroup), \
+ FN(get_hash_recalc), \
+ FN(get_current_task), \
+ FN(probe_write_user), \
+ FN(current_task_under_cgroup), \
+ FN(skb_change_tail), \
+ FN(skb_pull_data), \
+ FN(csum_update), \
+ FN(set_hash_invalid), \
+ FN(get_numa_node_id), \
+ FN(skb_change_head), \
+ FN(xdp_adjust_head), \
+ FN(probe_read_str), \
+ FN(get_socket_cookie), \
+ FN(get_socket_uid), \
+ FN(set_hash), \
+ FN(setsockopt), \
+ FN(skb_adjust_room), \
+ FN(redirect_map), \
+ FN(sk_redirect_map), \
+ FN(sock_map_update), \
+ FN(xdp_adjust_meta), \
+ FN(perf_event_read_value), \
+ FN(perf_prog_read_value), \
+ FN(getsockopt), \
+ FN(override_return), \
+ FN(sock_ops_cb_flags_set), \
+ FN(msg_redirect_map), \
+ FN(msg_apply_bytes), \
+ FN(msg_cork_bytes), \
+ FN(msg_pull_data), \
+ FN(bind), \
+ FN(xdp_adjust_tail), \
+ FN(skb_get_xfrm_state), \
+ FN(get_stack), \
+ FN(skb_load_bytes_relative), \
+ FN(fib_lookup), \
+ FN(sock_hash_update), \
+ FN(msg_redirect_hash), \
+ FN(sk_redirect_hash), \
+ FN(lwt_push_encap), \
+ FN(lwt_seg6_store_bytes), \
+ FN(lwt_seg6_adjust_srh), \
+ FN(lwt_seg6_action), \
+ FN(rc_repeat), \
+ FN(rc_keydown), \
+ FN(skb_cgroup_id), \
+ FN(get_current_cgroup_id), \
+ FN(get_local_storage), \
+ FN(sk_select_reuseport), \
+ FN(skb_ancestor_cgroup_id), \
+ FN(sk_lookup_tcp), \
+ FN(sk_lookup_udp), \
+ FN(sk_release), \
+ FN(map_push_elem), \
+ FN(map_pop_elem), \
+ FN(map_peek_elem), \
+ FN(msg_push_data), \
+ FN(msg_pop_data), \
+ FN(rc_pointer_rel), \
+ FN(spin_lock), \
+ FN(spin_unlock), \
+ FN(sk_fullsock), \
+ FN(tcp_sock), \
+ FN(skb_ecn_set_ce), \
+ FN(get_listener_sock), \
+ FN(skc_lookup_tcp), \
+ FN(tcp_check_syncookie), \
+ FN(sysctl_get_name), \
+ FN(sysctl_get_current_value), \
+ FN(sysctl_get_new_value), \
+ FN(sysctl_set_new_value), \
+ FN(strtol), \
+ FN(strtoul), \
+ FN(sk_storage_get), \
+ FN(sk_storage_delete), \
+ FN(send_signal),
+
+/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+ * function eBPF program intends to call
+ */
+#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
+enum bpf_func_id {
+ __BPF_FUNC_MAPPER(__BPF_ENUM_FN)
+ __BPF_FUNC_MAX_ID,
+};
+#undef __BPF_ENUM_FN
+
+/* End copy from linux/bpf.h */
+
+/* Start copy from tools/include/filter.h */
+
+#define BPF_ALU64_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_ALU32_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_ALU64_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_ALU32_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV64_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_MOV32_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_LD_IMM64(DST, IMM) \
+ BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_DW | BPF_IMM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = (uint32_t) (IMM) }), \
+ ((struct bpf_insn) { \
+ .code = 0, /* zero is reserved opcode */ \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((uint64_t) (IMM)) >> 32 })
+
+/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
+#define BPF_LD_MAP_FD(DST, MAP_FD) \
+ BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+#define BPF_MOV64_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV32_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_EMIT_CALL(FUNC) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_CALL, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((FUNC) - BPF_FUNC_unspec) })
+
+#define BPF_EXIT_INSN() \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_EXIT, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = 0 })
+
+/* End copy from tools/include/filter.h */
+
+/* Start copy from tools/lib/bpf */
+static inline uint64_t ptr_to_u64(const void *ptr)
+{
+ return (uint64_t) (unsigned long) ptr;
+}
+
+static inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size)
+{
+ return tst_syscall(__NR_bpf, cmd, attr, size);
+}
+/* End copy from tools/lib/bpf */
+
+#endif /* BPF_H */
diff --git a/src/kernel/tests/include/lapi/capability.h b/src/kernel/tests/include/lapi/capability.h
new file mode 100644
index 0000000..fde27ef
--- /dev/null
+++ b/src/kernel/tests/include/lapi/capability.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+#ifndef LAPI_CAPABILITY_H
+#define LAPI_CAPABILITY_H
+
+#include "config.h"
+
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+/**
+ * Some old libcap-devel(1.96~2.16) define _LINUX_TYPES_H in
+ * sys/capability.h that makes ltp-lib cann't include linux/types.h
+ * essentially. Here undefine it if include such old header-file.
+ */
+# ifndef HAVE_NEWER_LIBCAP
+# undef _LINUX_TYPES_H
+# endif
+#endif
+
+#ifndef CAP_NET_RAW
+# define CAP_NET_RAW 13
+#endif
+
+#ifndef CAP_SYS_ADMIN
+# define CAP_SYS_ADMIN 21
+#endif
+
+#ifndef CAP_SYS_TIME
+# define CAP_SYS_TIME 25
+#endif
+
+#ifndef CAP_AUDIT_READ
+# define CAP_AUDIT_READ 37
+#endif
+
+#ifndef CAP_SYS_RESOURCE
+# define CAP_SYS_RESOURCE 24
+#endif
+
+#ifndef CAP_TO_INDEX
+# define CAP_TO_INDEX(x) ((x) >> 5)
+#endif
+
+#ifndef CAP_TO_MASK
+# define CAP_TO_MASK(x) (1 << ((x) & 31))
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/clone.h b/src/kernel/tests/include/lapi/clone.h
new file mode 100644
index 0000000..2b8cbdb
--- /dev/null
+++ b/src/kernel/tests/include/lapi/clone.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef LAPI_CLONE_H__
+#define LAPI_CLONE_H__
+
+#include <sys/syscall.h>
+#include <linux/types.h>
+#include <sched.h>
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifndef HAVE_CLONE3
+struct clone_args {
+ uint64_t __attribute__((aligned(8))) flags;
+ uint64_t __attribute__((aligned(8))) pidfd;
+ uint64_t __attribute__((aligned(8))) child_tid;
+ uint64_t __attribute__((aligned(8))) parent_tid;
+ uint64_t __attribute__((aligned(8))) exit_signal;
+ uint64_t __attribute__((aligned(8))) stack;
+ uint64_t __attribute__((aligned(8))) stack_size;
+ uint64_t __attribute__((aligned(8))) tls;
+};
+
+int clone3(struct clone_args *args, size_t size)
+{
+ return tst_syscall(__NR_clone3, args, size);
+}
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000 /* set if a pidfd should be placed in parent */
+#endif
+
+void clone3_supported_by_kernel(void)
+{
+ if ((tst_kvercmp(5, 3, 0)) < 0) {
+ /* Check if the syscall is backported on an older kernel */
+ TEST(syscall(__NR_clone3, NULL, 0));
+ if (TST_RET == -1 && TST_ERR == ENOSYS)
+ tst_brk(TCONF, "Test not supported on kernel version < v5.3");
+ }
+}
+
+#endif /* LAPI_CLONE_H__ */
diff --git a/src/kernel/tests/include/lapi/common_timers.h b/src/kernel/tests/include/lapi/common_timers.h
new file mode 100644
index 0000000..b783bef
--- /dev/null
+++ b/src/kernel/tests/include/lapi/common_timers.h
@@ -0,0 +1,81 @@
+/*
+ * File: common_timers.h
+ *
+ * Keep all the common defines/checks for the timer tests here
+ */
+
+#ifndef __COMMON_TIMERS_H__
+#define __COMMON_TIMERS_H__
+
+#include "config.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC (1000000000L)
+#endif
+
+static const clock_t clock_list[] = {
+ CLOCK_REALTIME,
+ CLOCK_MONOTONIC,
+ CLOCK_PROCESS_CPUTIME_ID,
+ CLOCK_THREAD_CPUTIME_ID,
+ CLOCK_BOOTTIME,
+ CLOCK_BOOTTIME_ALARM,
+ CLOCK_REALTIME_ALARM,
+ CLOCK_TAI,
+};
+/* CLOCKS_DEFINED is the number of clock sources defined for sure */
+#define CLOCKS_DEFINED (sizeof(clock_list) / sizeof(*clock_list))
+/* MAX_CLOCKS is the maximum number of clock sources supported by kernel */
+#define MAX_CLOCKS 16
+
+#define CLOCK_TO_STR(def_name) \
+ case def_name: \
+ return #def_name;
+
+static inline const char *get_clock_str(const int clock_id)
+{
+ switch (clock_id) {
+ CLOCK_TO_STR(CLOCK_REALTIME);
+ CLOCK_TO_STR(CLOCK_MONOTONIC);
+ CLOCK_TO_STR(CLOCK_PROCESS_CPUTIME_ID);
+ CLOCK_TO_STR(CLOCK_THREAD_CPUTIME_ID);
+ CLOCK_TO_STR(CLOCK_BOOTTIME);
+ CLOCK_TO_STR(CLOCK_BOOTTIME_ALARM);
+ CLOCK_TO_STR(CLOCK_REALTIME_ALARM);
+ CLOCK_TO_STR(CLOCK_TAI);
+ default:
+ return "CLOCK_!?!?!?";
+ }
+}
+
+static inline int possibly_unsupported(clock_t clock)
+{
+ switch (clock) {
+ case CLOCK_BOOTTIME:
+ case CLOCK_BOOTTIME_ALARM:
+ case CLOCK_REALTIME_ALARM:
+ case CLOCK_TAI:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int have_cputime_timers(void)
+{
+ return tst_kvercmp(2, 6, 12) >= 0;
+}
+
+#include "lapi/syscalls.h"
+
+#include <time.h>
+#include <unistd.h>
+
+/* timer_t in kernel(int) is different from Glibc definition(void*).
+ * Use the kernel definition for syscall tests
+ */
+typedef int kernel_timer_t;
+
+#endif
diff --git a/src/kernel/tests/include/lapi/cpuset.h b/src/kernel/tests/include/lapi/cpuset.h
new file mode 100644
index 0000000..8f7136c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/cpuset.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
+ */
+
+/*
+ * Some old libcs (like glibc < 2.7) do not provide interfaces for
+ * dynamically sized cpu sets, but provide only static cpu_set_t type
+ * with no more than CPU_SETSIZE cpus in it.
+ *
+ * This file is a wrapper of the dynamic interfaces using the static ones.
+ *
+ * If the number of cpus available on the system is greater than
+ * CPU_SETSIZE, this interface will not work. Update libc in this case :)
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+
+#ifndef LTP_CPUSET_H
+#define LTP_CPUSET_H
+
+#ifndef CPU_ALLOC
+#define CPU_ALLOC(ncpus) malloc(sizeof(cpu_set_t)); \
+if (ncpus > CPU_SETSIZE) { \
+ tst_brk(TCONF, \
+ "Your libc does not support masks with %ld cpus", (long)ncpus); \
+}
+#endif
+
+#ifndef CPU_FREE
+#define CPU_FREE(ptr) free(ptr)
+#endif
+
+#ifndef CPU_ALLOC_SIZE
+#define CPU_ALLOC_SIZE(size) sizeof(cpu_set_t)
+#endif
+
+#ifndef CPU_ZERO_S
+#define CPU_ZERO_S(size, mask) CPU_ZERO(mask)
+#endif
+
+#ifndef CPU_SET_S
+#define CPU_SET_S(cpu, size, mask) CPU_SET(cpu, mask)
+#endif
+
+#ifndef CPU_ISSET_S
+#define CPU_ISSET_S(cpu, size, mask) CPU_ISSET(cpu, mask)
+#endif
+
+#endif /* LTP_CPUSET_H */
diff --git a/src/kernel/tests/include/lapi/cryptouser.h b/src/kernel/tests/include/lapi/cryptouser.h
new file mode 100644
index 0000000..e92fe96
--- /dev/null
+++ b/src/kernel/tests/include/lapi/cryptouser.h
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+#ifndef CRYPTOUSER_H__
+#define CRYPTOUSER_H__
+
+#ifdef HAVE_LINUX_CRYPTOUSER_H
+# include <linux/cryptouser.h>
+#else
+# include <stdint.h>
+# define CRYPTO_MAX_NAME 64
+
+enum {
+ CRYPTO_MSG_BASE = 0x10,
+ CRYPTO_MSG_NEWALG = 0x10,
+ CRYPTO_MSG_DELALG,
+ CRYPTO_MSG_UPDATEALG,
+ CRYPTO_MSG_GETALG,
+ CRYPTO_MSG_DELRNG,
+ __CRYPTO_MSG_MAX
+};
+
+enum crypto_attr_type_t {
+ CRYPTOCFGA_UNSPEC,
+ CRYPTOCFGA_PRIORITY_VAL, /* uint32_t */
+ CRYPTOCFGA_REPORT_LARVAL, /* struct crypto_report_larval */
+ CRYPTOCFGA_REPORT_HASH, /* struct crypto_report_hash */
+ CRYPTOCFGA_REPORT_BLKCIPHER, /* struct crypto_report_blkcipher */
+ CRYPTOCFGA_REPORT_AEAD, /* struct crypto_report_aead */
+ CRYPTOCFGA_REPORT_COMPRESS, /* struct crypto_report_comp */
+ CRYPTOCFGA_REPORT_RNG, /* struct crypto_report_rng */
+ CRYPTOCFGA_REPORT_CIPHER, /* struct crypto_report_cipher */
+ CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */
+ CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */
+ CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */
+ __CRYPTOCFGA_MAX
+
+#define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
+};
+
+struct crypto_user_alg {
+ char cru_name[CRYPTO_MAX_NAME];
+ char cru_driver_name[CRYPTO_MAX_NAME];
+ char cru_module_name[CRYPTO_MAX_NAME];
+ uint32_t cru_type;
+ uint32_t cru_mask;
+ uint32_t cru_refcnt;
+ uint32_t cru_flags;
+};
+
+struct crypto_report_larval {
+ char type[CRYPTO_MAX_NAME];
+};
+
+struct crypto_report_hash {
+ char type[CRYPTO_MAX_NAME];
+ unsigned int blocksize;
+ unsigned int digestsize;
+};
+
+struct crypto_report_cipher {
+ char type[CRYPTO_MAX_NAME];
+ unsigned int blocksize;
+ unsigned int min_keysize;
+ unsigned int max_keysize;
+};
+
+struct crypto_report_blkcipher {
+ char type[CRYPTO_MAX_NAME];
+ char geniv[CRYPTO_MAX_NAME];
+ unsigned int blocksize;
+ unsigned int min_keysize;
+ unsigned int max_keysize;
+ unsigned int ivsize;
+};
+
+struct crypto_report_aead {
+ char type[CRYPTO_MAX_NAME];
+ char geniv[CRYPTO_MAX_NAME];
+ unsigned int blocksize;
+ unsigned int maxauthsize;
+ unsigned int ivsize;
+};
+
+struct crypto_report_comp {
+ char type[CRYPTO_MAX_NAME];
+};
+
+struct crypto_report_rng {
+ char type[CRYPTO_MAX_NAME];
+ unsigned int seedsize;
+};
+
+struct crypto_report_akcipher {
+ char type[CRYPTO_MAX_NAME];
+};
+
+struct crypto_report_kpp {
+ char type[CRYPTO_MAX_NAME];
+};
+
+struct crypto_report_acomp {
+ char type[CRYPTO_MAX_NAME];
+};
+
+#endif /* HAVE_LINUX_CRYPTOUSER_H */
+
+/* These are taken from include/crypto.h in the kernel tree. They are not
+ * currently included in the user API.
+ */
+#ifndef CRYPTO_MAX_ALG_NAME
+# define CRYPTO_MAX_ALG_NAME 128
+#endif
+
+#ifndef CRYPTO_ALG_TYPE_MASK
+# define CRYPTO_ALG_TYPE_MASK 0x0000000f
+#endif
+#ifndef CRYPTO_ALG_TYPE_CIPHER
+# define CRYPTO_ALG_TYPE_CIPHER 0x00000001
+#endif
+#ifndef CRYPTO_ALG_TYPE_COMPRESS
+# define CRYPTO_ALG_TYPE_COMPRESS 0x00000002
+#endif
+#ifndef CRYPTO_ALG_TYPE_AEAD
+# define CRYPTO_ALG_TYPE_AEAD 0x00000003
+#endif
+#ifndef CRYPTO_ALG_TYPE_BLKCIPHER
+# define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004
+#endif
+#ifndef CRYPTO_ALG_TYPE_ABLKCIPHER
+# define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005
+#endif
+#ifndef CRYPTO_ALG_TYPE_SKCIPHER
+# define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005
+#endif
+#ifndef CRYPTO_ALG_TYPE_GIVCIPHER
+# define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006
+#endif
+#ifndef CRYPTO_ALG_TYPE_KPP
+# define CRYPTO_ALG_TYPE_KPP 0x00000008
+#endif
+#ifndef CRYPTO_ALG_TYPE_ACOMPRESS
+# define CRYPTO_ALG_TYPE_ACOMPRESS 0x0000000a
+#endif
+#ifndef CRYPTO_ALG_TYPE_SCOMPRESS
+# define CRYPTO_ALG_TYPE_SCOMPRESS 0x0000000b
+#endif
+#ifndef CRYPTO_ALG_TYPE_RNG
+# define CRYPTO_ALG_TYPE_RNG 0x0000000c
+#endif
+#ifndef CRYPTO_ALG_TYPE_AKCIPHER
+# define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d
+#endif
+#ifndef CRYPTO_ALG_TYPE_DIGEST
+# define CRYPTO_ALG_TYPE_DIGEST 0x0000000e
+#endif
+#ifndef CRYPTO_ALG_TYPE_HASH
+# define CRYPTO_ALG_TYPE_HASH 0x0000000e
+#endif
+#ifndef CRYPTO_ALG_TYPE_SHASH
+# define CRYPTO_ALG_TYPE_SHASH 0x0000000e
+#endif
+#ifndef CRYPTO_ALG_TYPE_AHASH
+# define CRYPTO_ALG_TYPE_AHASH 0x0000000f
+#endif
+
+#ifndef CRYPTO_ALG_TYPE_HASH_MASK
+# define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
+#endif
+#ifndef CRYPTO_ALG_TYPE_AHASH_MASK
+# define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e
+#endif
+#ifndef CRYPTO_ALG_TYPE_BLKCIPHER_MASK
+# define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c
+#endif
+#ifndef CRYPTO_ALG_TYPE_ACOMPRESS_MASK
+# define CRYPTO_ALG_TYPE_ACOMPRESS_MASK 0x0000000e
+#endif
+
+#endif /* CRYPTOUSER_H__ */
diff --git a/src/kernel/tests/include/lapi/dccp.h b/src/kernel/tests/include/lapi/dccp.h
new file mode 100644
index 0000000..a0f0148
--- /dev/null
+++ b/src/kernel/tests/include/lapi/dccp.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef LAPI_DCCP_H__
+#define LAPI_DCCP_H__
+
+#ifdef HAVE_LINUX_DCCP_H
+# include <linux/dccp.h>
+#endif
+
+#ifndef DCCP_SOCKOPT_SERVICE
+# define DCCP_SOCKOPT_SERVICE 2
+#endif
+
+#endif /* LAPI_DCCP_H__ */
diff --git a/src/kernel/tests/include/lapi/epoll.h b/src/kernel/tests/include/lapi/epoll.h
new file mode 100644
index 0000000..899eeb9
--- /dev/null
+++ b/src/kernel/tests/include/lapi/epoll.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef LAPI_EPOLL_H__
+#define LAPI_EPOLL_H__
+
+#ifndef EPOLL_CLOEXEC
+# define EPOLL_CLOEXEC 02000000
+#endif
+
+#endif /* LAPI_EPOLL_H__ */
diff --git a/src/kernel/tests/include/lapi/execveat.h b/src/kernel/tests/include/lapi/execveat.h
new file mode 100644
index 0000000..a7406f7
--- /dev/null
+++ b/src/kernel/tests/include/lapi/execveat.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
+ */
+
+#ifndef EXECVEAT_H
+#define EXECVEAT_H
+
+#include <sys/types.h>
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_EXECVEAT)
+int execveat(int dirfd, const char *pathname,
+ char *const argv[], char *const envp[],
+ int flags)
+{
+ return tst_syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
+}
+#endif
+
+#endif /* EXECVEAT_H */
diff --git a/src/kernel/tests/include/lapi/fallocate.h b/src/kernel/tests/include/lapi/fallocate.h
new file mode 100644
index 0000000..72f52c7
--- /dev/null
+++ b/src/kernel/tests/include/lapi/fallocate.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ */
+
+#ifndef FALLOCATE_H
+#define FALLOCATE_H
+
+#include <sys/types.h>
+#include <endian.h>
+#include "config.h"
+#include "lapi/abisize.h"
+#include "lapi/seek.h"
+#include "lapi/syscalls.h"
+
+#ifndef FALLOC_FL_KEEP_SIZE
+# define FALLOC_FL_KEEP_SIZE 0x01
+#endif
+
+#ifndef FALLOC_FL_PUNCH_HOLE
+# define FALLOC_FL_PUNCH_HOLE 0x02
+#endif
+
+#ifndef FALLOC_FL_COLLAPSE_RANGE
+# define FALLOC_FL_COLLAPSE_RANGE 0x08
+#endif
+
+#ifndef FALLOC_FL_ZERO_RANGE
+# define FALLOC_FL_ZERO_RANGE 0x10
+#endif
+
+#ifndef FALLOC_FL_INSERT_RANGE
+# define FALLOC_FL_INSERT_RANGE 0x20
+#endif
+
+#if !defined(HAVE_FALLOCATE)
+
+# ifdef __TEST_H__
+# define TST_SYSCALL_WRAPPER ltp_syscall
+# else
+# define TST_SYSCALL_WRAPPER tst_syscall
+# endif /* __TEST_H__ */
+
+static inline long fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+ /* Deal with 32bit ABIs that have 64bit syscalls. */
+# if LTP_USE_64_ABI
+ return TST_SYSCALL_WRAPPER(__NR_fallocate, fd, mode, offset, len);
+# else
+ return (long)TST_SYSCALL_WRAPPER(__NR_fallocate, fd, mode,
+ __LONG_LONG_PAIR((off_t) (offset >> 32),
+ (off_t) offset),
+ __LONG_LONG_PAIR((off_t) (len >> 32),
+ (off_t) len));
+# endif
+}
+#endif
+
+#endif /* FALLOCATE_H */
diff --git a/src/kernel/tests/include/lapi/fcntl.h b/src/kernel/tests/include/lapi/fcntl.h
new file mode 100644
index 0000000..576a18d
--- /dev/null
+++ b/src/kernel/tests/include/lapi/fcntl.h
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef __LAPI_FCNTL_H__
+#define __LAPI_FCNTL_H__
+
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#ifndef O_DIRECT
+# define O_DIRECT 040000
+#endif
+
+#ifndef O_CLOEXEC
+# define O_CLOEXEC 02000000
+#endif
+
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC O_CLOEXEC
+#endif
+
+#ifndef SOCK_NONBLOCK
+# define SOCK_NONBLOCK O_NONBLOCK
+#endif
+
+#ifndef O_TMPFILE
+# define O_TMPFILE (020000000 | O_DIRECTORY)
+#endif
+
+#ifndef F_DUPFD_CLOEXEC
+# define F_DUPFD_CLOEXEC 1030
+#endif
+
+#ifndef F_SETPIPE_SZ
+# define F_SETPIPE_SZ 1031
+#endif
+
+#ifndef F_GETPIPE_SZ
+# define F_GETPIPE_SZ 1032
+#endif
+
+/*
+ * Set/Get seals
+ */
+#ifndef F_ADD_SEALS
+# define F_ADD_SEALS (1033)
+#endif
+
+#ifndef F_GET_SEALS
+# define F_GET_SEALS (1034)
+#endif
+
+#ifndef F_SEAL_SEAL
+# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+#endif
+
+#ifndef F_SEAL_SHRINK
+# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+#endif
+#ifndef F_SEAL_GROW
+# define F_SEAL_GROW 0x0004 /* prevent file from growing */
+#endif
+#ifndef F_SEAL_WRITE
+# define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+#ifndef F_OWNER_PGRP
+# define F_OWNER_PGRP 2
+#endif
+
+#ifndef F_OFD_GETLK
+# define F_OFD_GETLK 36
+#endif
+
+#ifndef F_OFD_SETLK
+# define F_OFD_SETLK 37
+#endif
+
+#ifndef F_OFD_SETLKW
+# define F_OFD_SETLKW 38
+#endif
+
+#ifndef AT_FDCWD
+# define AT_FDCWD -100
+#endif
+
+#ifndef AT_SYMLINK_FOLLOW
+# define AT_SYMLINK_FOLLOW 0x400
+#endif
+
+#ifndef AT_SYMLINK_NOFOLLOW
+# define AT_SYMLINK_NOFOLLOW 0x100
+#endif
+
+#ifndef AT_EMPTY_PATH
+# define AT_EMPTY_PATH 0x1000
+#endif
+
+#ifndef AT_REMOVEDIR
+# define AT_REMOVEDIR 0x200
+#endif
+
+#ifndef O_NOATIME
+# define O_NOATIME 01000000
+#endif
+
+#ifndef O_PATH
+# ifdef __sparc__
+# define O_PATH 0x1000000
+# else
+# define O_PATH 010000000
+# endif
+#endif
+
+#ifndef FALLOC_FL_KEEP_SIZE
+# define FALLOC_FL_KEEP_SIZE 1
+#endif
+
+#ifndef RENAME_NOREPLACE
+# define RENAME_NOREPLACE (1 << 0)
+#endif
+
+#ifndef RENAME_EXCHANGE
+# define RENAME_EXCHANGE (1 << 1)
+#endif
+
+#ifndef RENAME_WHITEOUT
+# define RENAME_WHITEOUT (1 << 2)
+#endif
+
+/* splice, vmsplice, tee */
+
+#ifndef SPLICE_F_NONBLOCK
+# define SPLICE_F_NONBLOCK 2
+#endif
+
+#endif /* __LAPI_FCNTL_H__ */
diff --git a/src/kernel/tests/include/lapi/fnmatch.h b/src/kernel/tests/include/lapi/fnmatch.h
new file mode 100644
index 0000000..9628ac4
--- /dev/null
+++ b/src/kernel/tests/include/lapi/fnmatch.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#ifndef FNMATCH_H__
+#define FNMATCH_H__
+
+#ifndef FNM_EXTMATCH
+#define FNM_EXTMATCH 0
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/fs.h b/src/kernel/tests/include/lapi/fs.h
new file mode 100644
index 0000000..430d21f
--- /dev/null
+++ b/src/kernel/tests/include/lapi/fs.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Referred from linux kernel include/uapi/linux/fs.h
+ * Copyright (c) 2019 Petr Vorel <pvorel@suse.cz>
+ * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
+ * Email: code@zilogic.com
+ */
+
+#ifdef HAVE_LINUX_FS_H
+# include <linux/fs.h>
+#endif
+
+#include <sys/user.h>
+#include <limits.h>
+#include "lapi/abisize.h"
+
+#ifndef LAPI_FS_H
+#define LAPI_FS_H
+
+#ifndef FS_IOC_GETFLAGS
+#define FS_IOC_GETFLAGS _IOR('f', 1, long)
+#endif
+
+#ifndef FS_IOC_SETFLAGS
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+#endif
+
+#ifndef FS_COMPR_FL
+#define FS_COMPR_FL 0x00000004 /* Compress file */
+#endif
+
+#ifndef FS_IMMUTABLE_FL
+#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#endif
+
+#ifndef FS_APPEND_FL
+#define FS_APPEND_FL 0x00000020 /* writes to file may only append */
+#endif
+
+#ifndef FS_NODUMP_FL
+#define FS_NODUMP_FL 0x00000040 /* do not dump file */
+#endif
+
+/*
+ * Helper function to get MAX_LFS_FILESIZE.
+ * Missing PAGE_SHIFT on some libc prevents defining MAX_LFS_FILESIZE.
+ *
+ * 64 bit: macro taken from kernel from include/linux/fs.h
+ * 32 bit: own implementation
+ */
+static inline loff_t tst_max_lfs_filesize(void)
+{
+#ifdef TST_ABI64
+ return (loff_t)LLONG_MAX;
+#else
+ long page_size = getpagesize();
+ loff_t ret = ULONG_MAX;
+
+ while (page_size >>= 1)
+ ret <<= 1;
+
+ return ret;
+#endif
+}
+
+#endif
diff --git a/src/kernel/tests/include/lapi/fsmount.h b/src/kernel/tests/include/lapi/fsmount.h
new file mode 100644
index 0000000..09a2c16
--- /dev/null
+++ b/src/kernel/tests/include/lapi/fsmount.h
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef FSMOUNT_H__
+#define FSMOUNT_H__
+
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "lapi/fcntl.h"
+#include "lapi/syscalls.h"
+
+#ifndef HAVE_FSOPEN
+int fsopen(const char *fsname, unsigned int flags)
+{
+ return tst_syscall(__NR_fsopen, fsname, flags);
+}
+#endif /* HAVE_FSOPEN */
+
+#ifndef HAVE_FSCONFIG
+int fsconfig(int fd, unsigned int cmd, const char *key,
+ const void *value, int aux)
+{
+ return tst_syscall(__NR_fsconfig, fd, cmd, key, value, aux);
+}
+#endif /* HAVE_FSCONFIG */
+
+#ifndef HAVE_FSMOUNT
+int fsmount(int fd, unsigned int flags, unsigned int mount_attrs)
+{
+ return tst_syscall(__NR_fsmount, fd, flags, mount_attrs);
+}
+#endif /* HAVE_FSMOUNT */
+
+#ifndef HAVE_FSPICK
+int fspick(int dirfd, const char *pathname, unsigned int flags)
+{
+ return tst_syscall(__NR_fspick, dirfd, pathname, flags);
+}
+#endif /* HAVE_FSPICK */
+
+#ifndef HAVE_MOVE_MOUNT
+int move_mount(int from_dirfd, const char *from_pathname, int to_dirfd,
+ const char *to_pathname, unsigned int flags)
+{
+ return tst_syscall(__NR_move_mount, from_dirfd, from_pathname, to_dirfd,
+ to_pathname, flags);
+}
+#endif /* HAVE_MOVE_MOUNT */
+
+#ifndef HAVE_OPEN_TREE
+int open_tree(int dirfd, const char *pathname, unsigned int flags)
+{
+ return tst_syscall(__NR_open_tree, dirfd, pathname, flags);
+}
+#endif /* HAVE_OPEN_TREE */
+
+/*
+ * New headers added in kernel after 5.2 release, create them for old userspace.
+*/
+
+#ifndef OPEN_TREE_CLONE
+
+/*
+ * open_tree() flags.
+ */
+#define OPEN_TREE_CLONE 1 /* Clone the target tree and attach the clone */
+#define OPEN_TREE_CLOEXEC O_CLOEXEC /* Close the file on execve() */
+
+/*
+ * move_mount() flags.
+ */
+#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
+#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
+#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
+#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
+#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
+#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
+#define MOVE_MOUNT__MASK 0x00000077
+
+/*
+ * fsopen() flags.
+ */
+#define FSOPEN_CLOEXEC 0x00000001
+
+/*
+ * fspick() flags.
+ */
+#define FSPICK_CLOEXEC 0x00000001
+#define FSPICK_SYMLINK_NOFOLLOW 0x00000002
+#define FSPICK_NO_AUTOMOUNT 0x00000004
+#define FSPICK_EMPTY_PATH 0x00000008
+
+/*
+ * The type of fsconfig() call made.
+ */
+enum fsconfig_command {
+ FSCONFIG_SET_FLAG = 0, /* Set parameter, supplying no value */
+ FSCONFIG_SET_STRING = 1, /* Set parameter, supplying a string value */
+ FSCONFIG_SET_BINARY = 2, /* Set parameter, supplying a binary blob value */
+ FSCONFIG_SET_PATH = 3, /* Set parameter, supplying an object by path */
+ FSCONFIG_SET_PATH_EMPTY = 4, /* Set parameter, supplying an object by (empty) path */
+ FSCONFIG_SET_FD = 5, /* Set parameter, supplying an object by fd */
+ FSCONFIG_CMD_CREATE = 6, /* Invoke superblock creation */
+ FSCONFIG_CMD_RECONFIGURE = 7, /* Invoke superblock reconfiguration */
+};
+
+/*
+ * fsmount() flags.
+ */
+#define FSMOUNT_CLOEXEC 0x00000001
+
+/*
+ * Mount attributes.
+ */
+#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
+#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */
+#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */
+#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */
+#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */
+#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */
+#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */
+#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */
+#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */
+
+#endif /* OPEN_TREE_CLONE */
+
+void fsopen_supported_by_kernel(void)
+{
+ if ((tst_kvercmp(5, 2, 0)) < 0) {
+ /* Check if the syscall is backported on an older kernel */
+ TEST(syscall(__NR_fsopen, NULL, 0));
+ if (TST_RET != -1)
+ SAFE_CLOSE(TST_RET);
+ else if (TST_ERR == ENOSYS)
+ tst_brk(TCONF, "Test not supported on kernel version < v5.2");
+ }
+}
+
+#endif /* FSMOUNT_H__ */
diff --git a/src/kernel/tests/include/lapi/futex.h b/src/kernel/tests/include/lapi/futex.h
new file mode 100644
index 0000000..72209e4
--- /dev/null
+++ b/src/kernel/tests/include/lapi/futex.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Linux Test Project
+ */
+
+#ifndef LAPI_FUTEX_H__
+#define LAPI_FUTEX_H__
+
+#include <stdint.h>
+
+typedef volatile uint32_t futex_t;
+
+#endif /* LAPI_FUTEX_H__ */
diff --git a/src/kernel/tests/include/lapi/getrandom.h b/src/kernel/tests/include/lapi/getrandom.h
new file mode 100644
index 0000000..83e0a0e
--- /dev/null
+++ b/src/kernel/tests/include/lapi/getrandom.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Linux Test Project
+ */
+
+#ifndef __GETRANDOM_H__
+#define __GETRANDOM_H__
+
+#include "config.h"
+
+#if HAVE_LINUX_RANDOM_H
+#include <linux/random.h>
+#endif
+
+/*
+ * Flags for getrandom(2)
+ *
+ * GRND_NONBLOCK Don't block and return EAGAIN instead
+ * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom
+ */
+
+#ifndef GRND_NONBLOCK
+# define GRND_NONBLOCK 0x0001
+#endif
+
+#ifndef GRND_RANDOM
+# define GRND_RANDOM 0x0002
+#endif
+
+#endif /* __GETRANDOM_H__ */
diff --git a/src/kernel/tests/include/lapi/if_alg.h b/src/kernel/tests/include/lapi/if_alg.h
new file mode 100644
index 0000000..9c04a44
--- /dev/null
+++ b/src/kernel/tests/include/lapi/if_alg.h
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef IF_ALG_H__
+#define IF_ALG_H__
+
+#ifdef HAVE_LINUX_IF_ALG_H
+# include <linux/if_alg.h>
+#endif
+# include <stdint.h>
+
+#ifndef HAVE_STRUCT_SOCKADDR_ALG
+struct sockaddr_alg {
+ uint16_t salg_family;
+ uint8_t salg_type[14];
+ uint32_t salg_feat;
+ uint32_t salg_mask;
+ uint8_t salg_name[64];
+};
+#endif
+
+#ifndef HAVE_STRUCT_AF_ALG_IV
+struct af_alg_iv {
+ uint32_t ivlen;
+ uint8_t iv[0];
+};
+#endif
+
+#ifndef ALG_SET_KEY
+# define ALG_SET_KEY 1
+#endif
+
+#ifndef ALG_SET_IV
+# define ALG_SET_IV 2
+#endif
+
+#ifndef ALG_SET_OP
+# define ALG_SET_OP 3
+#endif
+
+#ifndef ALG_SET_AEAD_ASSOCLEN
+# define ALG_SET_AEAD_ASSOCLEN 4
+#endif
+
+#ifndef ALG_SET_AEAD_AUTHSIZE
+# define ALG_SET_AEAD_AUTHSIZE 5
+#endif
+
+#ifndef ALG_OP_DECRYPT
+# define ALG_OP_DECRYPT 0
+#endif
+
+#ifndef ALG_OP_ENCRYPT
+# define ALG_OP_ENCRYPT 1
+#endif
+
+#endif /* IF_ALG_H__ */
diff --git a/src/kernel/tests/include/lapi/if_ether.h b/src/kernel/tests/include/lapi/if_ether.h
new file mode 100644
index 0000000..0e9a4fc
--- /dev/null
+++ b/src/kernel/tests/include/lapi/if_ether.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
+ */
+
+#ifndef __LAPI_IF_ETHER_H__
+#define __LAPI_IF_ETHER_H__
+
+#include "config.h"
+
+#ifdef HAVE_LINUX_IF_ETHER_H
+# include <linux/if_ether.h>
+#endif
+
+#ifndef ETH_P_ALL
+# define ETH_P_ALL 0x0003
+#endif
+
+#endif /* __LAPI_IF_ETHER_H__ */
diff --git a/src/kernel/tests/include/lapi/if_packet.h b/src/kernel/tests/include/lapi/if_packet.h
new file mode 100644
index 0000000..8111021
--- /dev/null
+++ b/src/kernel/tests/include/lapi/if_packet.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Author: Jinhui huang <huangjh.jy@cn.fujitsu.com>
+ */
+
+#ifndef __LAPI_IF_PACKET_H__
+#define __LAPI_IF_PACKET_H__
+
+#include "config.h"
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+# include <linux/if_packet.h>
+#endif
+
+#ifndef PACKET_RX_RING
+# define PACKET_RX_RING 5
+#endif
+
+#ifndef PACKET_VERSION
+# define PACKET_VERSION 10
+#endif
+
+#ifndef PACKET_RESERVE
+# define PACKET_RESERVE 12
+#endif
+
+#ifndef PACKET_FANOUT
+#define PACKET_FANOUT 18
+#endif
+
+#ifndef PACKET_FANOUT_ROLLOVER
+#define PACKET_FANOUT_ROLLOVER 3
+#endif
+
+#ifndef HAVE_STRUCT_TPACKET_REQ3
+# define TPACKET_V3 2
+
+struct tpacket_req3 {
+ unsigned int tp_block_size;
+ unsigned int tp_block_nr;
+ unsigned int tp_frame_size;
+ unsigned int tp_frame_nr;
+ unsigned int tp_retire_blk_tov;
+ unsigned int tp_sizeof_priv;
+ unsigned int tp_feature_req_word;
+};
+#endif
+
+#endif /* __LAPI_IF_PACKET_H__ */
diff --git a/src/kernel/tests/include/lapi/io_pgetevents.h b/src/kernel/tests/include/lapi/io_pgetevents.h
new file mode 100644
index 0000000..5bb9a60
--- /dev/null
+++ b/src/kernel/tests/include/lapi/io_pgetevents.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef IO_PGETEVENTS_H
+#define IO_PGETEVENTS_H
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifdef HAVE_LIBAIO
+#include <libaio.h>
+
+static inline int sys_io_pgetevents(io_context_t ctx, long min_nr, long max_nr,
+ struct io_event *events, void *timeout, sigset_t *sigmask)
+{
+ return tst_syscall(__NR_io_pgetevents, ctx, min_nr, max_nr, events,
+ timeout, sigmask);
+}
+
+static inline int sys_io_pgetevents_time64(io_context_t ctx, long min_nr, long max_nr,
+ struct io_event *events, void *timeout, sigset_t *sigmask)
+{
+ return tst_syscall(__NR_io_pgetevents_time64, ctx, min_nr, max_nr,
+ events, timeout, sigmask);
+}
+
+#endif /* HAVE_LIBAIO */
+
+#endif /* IO_PGETEVENTS_H */
diff --git a/src/kernel/tests/include/lapi/io_uring.h b/src/kernel/tests/include/lapi/io_uring.h
new file mode 100644
index 0000000..174e81e
--- /dev/null
+++ b/src/kernel/tests/include/lapi/io_uring.h
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 ARM. All rights reserved.
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ *
+ * Mostly copied/adapted from <linux/io_uring.h>
+ */
+
+#ifndef IO_URING_H__
+#define IO_URING_H__
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+
+#include "lapi/syscalls.h"
+
+#ifndef IOSQE_FIXED_FILE
+
+#ifndef __kernel_rwf_t
+typedef int __kernel_rwf_t;
+#endif
+
+/*
+ * IO submission data structure (Submission Queue Entry)
+ */
+struct io_uring_sqe {
+ uint8_t opcode; /* type of operation for this sqe */
+ uint8_t flags; /* IOSQE_ flags */
+ uint16_t ioprio; /* ioprio for the request */
+ int32_t fd; /* file descriptor to do IO on */
+ union {
+ uint64_t off; /* offset into file */
+ uint64_t addr2;
+ };
+ uint64_t addr; /* pointer to buffer or iovecs */
+ uint32_t len; /* buffer size or number of iovecs */
+ union {
+ __kernel_rwf_t rw_flags;
+ uint32_t fsync_flags;
+ uint16_t poll_events;
+ uint32_t sync_range_flags;
+ uint32_t msg_flags;
+ uint32_t timeout_flags;
+ uint32_t accept_flags;
+ uint32_t cancel_flags;
+ uint32_t open_flags;
+ uint32_t statx_flags;
+ uint32_t fadvise_advice;
+ };
+ uint64_t user_data; /* data to be passed back at completion time */
+ union {
+ struct {
+ /* index into fixed buffers, if used */
+ uint16_t buf_index;
+ /* personality to use, if used */
+ uint16_t personality;
+ };
+ uint64_t __pad2[3];
+ };
+};
+
+enum {
+ IOSQE_FIXED_FILE_BIT,
+ IOSQE_IO_DRAIN_BIT,
+ IOSQE_IO_LINK_BIT,
+ IOSQE_IO_HARDLINK_BIT,
+ IOSQE_ASYNC_BIT,
+};
+
+/*
+ * sqe->flags
+ */
+/* use fixed fileset */
+#define IOSQE_FIXED_FILE (1U << IOSQE_FIXED_FILE_BIT)
+/* issue after inflight IO */
+#define IOSQE_IO_DRAIN (1U << IOSQE_IO_DRAIN_BIT)
+/* links next sqe */
+#define IOSQE_IO_LINK (1U << IOSQE_IO_LINK_BIT)
+/* like LINK, but stronger */
+#define IOSQE_IO_HARDLINK (1U << IOSQE_IO_HARDLINK_BIT)
+/* always go async */
+#define IOSQE_ASYNC (1U << IOSQE_ASYNC_BIT)
+
+/*
+ * io_uring_setup() flags
+ */
+#define IORING_SETUP_IOPOLL (1U << 0) /* io_context is polled */
+#define IORING_SETUP_SQPOLL (1U << 1) /* SQ poll thread */
+#define IORING_SETUP_SQ_AFF (1U << 2) /* sq_thread_cpu is valid */
+#define IORING_SETUP_CQSIZE (1U << 3) /* app defines CQ size */
+#define IORING_SETUP_CLAMP (1U << 4) /* clamp SQ/CQ ring sizes */
+#define IORING_SETUP_ATTACH_WQ (1U << 5) /* attach to existing wq */
+
+enum {
+ IORING_OP_NOP,
+ IORING_OP_READV,
+ IORING_OP_WRITEV,
+ IORING_OP_FSYNC,
+ IORING_OP_READ_FIXED,
+ IORING_OP_WRITE_FIXED,
+ IORING_OP_POLL_ADD,
+ IORING_OP_POLL_REMOVE,
+ IORING_OP_SYNC_FILE_RANGE,
+ IORING_OP_SENDMSG,
+ IORING_OP_RECVMSG,
+ IORING_OP_TIMEOUT,
+ IORING_OP_TIMEOUT_REMOVE,
+ IORING_OP_ACCEPT,
+ IORING_OP_ASYNC_CANCEL,
+ IORING_OP_LINK_TIMEOUT,
+ IORING_OP_CONNECT,
+ IORING_OP_FALLOCATE,
+ IORING_OP_OPENAT,
+ IORING_OP_CLOSE,
+ IORING_OP_FILES_UPDATE,
+ IORING_OP_STATX,
+ IORING_OP_READ,
+ IORING_OP_WRITE,
+ IORING_OP_FADVISE,
+ IORING_OP_MADVISE,
+ IORING_OP_SEND,
+ IORING_OP_RECV,
+ IORING_OP_OPENAT2,
+ IORING_OP_EPOLL_CTL,
+
+ /* this goes last, obviously */
+ IORING_OP_LAST,
+};
+
+/*
+ * sqe->fsync_flags
+ */
+#define IORING_FSYNC_DATASYNC (1U << 0)
+
+/*
+ * sqe->timeout_flags
+ */
+#define IORING_TIMEOUT_ABS (1U << 0)
+
+/*
+ * IO completion data structure (Completion Queue Entry)
+ */
+struct io_uring_cqe {
+ uint64_t user_data; /* sqe->data submission passed back */
+ int32_t res; /* result code for this event */
+ uint32_t flags;
+};
+
+/*
+ * Magic offsets for the application to mmap the data it needs
+ */
+#define IORING_OFF_SQ_RING 0ULL
+#define IORING_OFF_CQ_RING 0x8000000ULL
+#define IORING_OFF_SQES 0x10000000ULL
+
+/*
+ * Filled with the offset for mmap(2)
+ */
+struct io_sqring_offsets {
+ uint32_t head;
+ uint32_t tail;
+ uint32_t ring_mask;
+ uint32_t ring_entries;
+ uint32_t flags;
+ uint32_t dropped;
+ uint32_t array;
+ uint32_t resv1;
+ uint64_t resv2;
+};
+
+/*
+ * sq_ring->flags
+ */
+#define IORING_SQ_NEED_WAKEUP (1U << 0) /* needs io_uring_enter wakeup */
+
+struct io_cqring_offsets {
+ uint32_t head;
+ uint32_t tail;
+ uint32_t ring_mask;
+ uint32_t ring_entries;
+ uint32_t overflow;
+ uint32_t cqes;
+ uint64_t resv[2];
+};
+
+/*
+ * io_uring_enter(2) flags
+ */
+#define IORING_ENTER_GETEVENTS (1U << 0)
+#define IORING_ENTER_SQ_WAKEUP (1U << 1)
+
+/*
+ * Passed in for io_uring_setup(2). Copied back with updated info on success
+ */
+struct io_uring_params {
+ uint32_t sq_entries;
+ uint32_t cq_entries;
+ uint32_t flags;
+ uint32_t sq_thread_cpu;
+ uint32_t sq_thread_idle;
+ uint32_t features;
+ uint32_t wq_fd;
+ uint32_t resv[3];
+ struct io_sqring_offsets sq_off;
+ struct io_cqring_offsets cq_off;
+};
+
+/*
+ * io_uring_params->features flags
+ */
+#define IORING_FEAT_SINGLE_MMAP (1U << 0)
+#define IORING_FEAT_NODROP (1U << 1)
+#define IORING_FEAT_SUBMIT_STABLE (1U << 2)
+#define IORING_FEAT_RW_CUR_POS (1U << 3)
+#define IORING_FEAT_CUR_PERSONALITY (1U << 4)
+
+/*
+ * io_uring_register(2) opcodes and arguments
+ */
+#define IORING_REGISTER_BUFFERS 0
+#define IORING_UNREGISTER_BUFFERS 1
+#define IORING_REGISTER_FILES 2
+#define IORING_UNREGISTER_FILES 3
+#define IORING_REGISTER_EVENTFD 4
+#define IORING_UNREGISTER_EVENTFD 5
+#define IORING_REGISTER_FILES_UPDATE 6
+#define IORING_REGISTER_EVENTFD_ASYNC 7
+#define IORING_REGISTER_PROBE 8
+#define IORING_REGISTER_PERSONALITY 9
+#define IORING_UNREGISTER_PERSONALITY 10
+
+struct io_uring_files_update {
+ uint32_t offset;
+ uint32_t resv;
+ uint64_t __attribute__((aligned(8))) fds;
+};
+
+#define IO_URING_OP_SUPPORTED (1U << 0)
+
+struct io_uring_probe_op {
+ uint8_t op;
+ uint8_t resv;
+ uint16_t flags; /* IO_URING_OP_* flags */
+ uint32_t resv2;
+};
+
+struct io_uring_probe {
+ uint8_t last_op; /* last opcode supported */
+ uint8_t ops_len; /* length of ops[] array below */
+ uint16_t resv;
+ uint32_t resv2[3];
+ struct io_uring_probe_op ops[0];
+};
+
+#endif /* IOSQE_FIXED_FILE */
+
+
+#ifndef HAVE_IO_URING_REGISTER
+int io_uring_register(int fd, unsigned int opcode, void *arg,
+ unsigned int nr_args)
+{
+ return tst_syscall(__NR_io_uring_register, fd, opcode, arg, nr_args);
+}
+#endif /* HAVE_IO_URING_REGISTER */
+
+
+#ifndef HAVE_IO_URING_SETUP
+int io_uring_setup(unsigned int entries, struct io_uring_params *p)
+{
+ return tst_syscall(__NR_io_uring_setup, entries, p);
+}
+#endif /* HAVE_IO_URING_SETUP */
+
+#ifndef HAVE_IO_URING_ENTER
+int io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete,
+ unsigned int flags, sigset_t *sig)
+{
+ return tst_syscall(__NR_io_uring_enter, fd, to_submit, min_complete,
+ flags, sig, _NSIG / 8);
+}
+#endif /* HAVE_IO_URING_ENTER */
+
+void io_uring_setup_supported_by_kernel(void)
+{
+ if ((tst_kvercmp(5, 1, 0)) < 0) {
+ TEST(syscall(__NR_io_uring_setup, NULL, 0));
+ if (TST_RET != -1)
+ SAFE_CLOSE(TST_RET);
+ else if (TST_ERR == ENOSYS)
+ tst_brk(TCONF,
+ "Test not supported on kernel version < v5.1");
+ }
+}
+
+#endif /* IO_URING_H__ */
diff --git a/src/kernel/tests/include/lapi/ioctl.h b/src/kernel/tests/include/lapi/ioctl.h
new file mode 100644
index 0000000..ecd2502
--- /dev/null
+++ b/src/kernel/tests/include/lapi/ioctl.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef IOCTL_H__
+#define IOCTL_H__
+
+#include "config.h"
+#include <sys/ioctl.h>
+
+/* musl not including it in <sys/ioctl.h> */
+#include <sys/ttydefaults.h>
+
+#ifndef TIOCVHANGUP
+# define TIOCVHANGUP 0x5437
+#endif
+
+#ifndef HAVE_STRUCT_TERMIO
+# ifndef NCC
+# ifdef __powerpc__
+# define NCC 10
+# else
+# define NCC 8
+# endif
+# endif /* NCC */
+
+struct termio
+ {
+ unsigned short int c_iflag; /* input mode flags */
+ unsigned short int c_oflag; /* output mode flags */
+ unsigned short int c_cflag; /* control mode flags */
+ unsigned short int c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+#endif /* HAVE_STRUCT_TERMIO */
+
+#endif /* IOCTL_H__ */
diff --git a/src/kernel/tests/include/lapi/ioctl_ns.h b/src/kernel/tests/include/lapi/ioctl_ns.h
new file mode 100644
index 0000000..2fb4f4c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/ioctl_ns.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+#ifndef IOCTL_NS_H__
+#define IOCTL_NS_H__
+
+#include <asm-generic/ioctl.h>
+
+#ifndef NSIO
+#define NSIO 0xb7
+#endif
+#ifndef NS_GET_PARENT
+#define NS_GET_PARENT _IO(NSIO, 0x2)
+#endif
+#ifndef NS_GET_OWNER_UID
+#define NS_GET_OWNER_UID _IO(NSIO, 0x4)
+#endif
+#ifndef NS_GET_USERNS
+#define NS_GET_USERNS _IO(NSIO, 0x1)
+#endif
+#ifndef NS_GET_NSTYPE
+#define NS_GET_NSTYPE _IO(NSIO, 0x3)
+#endif
+
+
+#endif /* IOCTL_NS_H__ */
diff --git a/src/kernel/tests/include/lapi/iovec.h b/src/kernel/tests/include/lapi/iovec.h
new file mode 100644
index 0000000..d479e9f
--- /dev/null
+++ b/src/kernel/tests/include/lapi/iovec.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef IOVEC_H
+#define IOVEC_H
+
+#include "config.h"
+
+#if !defined(HAVE_STRUCT_IOVEC)
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+#else
+# include <sys/uio.h>
+#endif
+
+#endif /* IOVEC_H */
diff --git a/src/kernel/tests/include/lapi/ipcbuf.h b/src/kernel/tests/include/lapi/ipcbuf.h
new file mode 100644
index 0000000..a0b8e3c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/ipcbuf.h
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef IPCBUF_H
+#define IPCBUF_H
+
+#include "config.h"
+#include "lapi/posix_types.h"
+
+#ifndef HAVE_IPC64_PERM
+
+#if defined(__hppa__)
+#define HAVE_IPC64_PERM
+/*
+ * The ipc64_perm structure for PA-RISC is almost identical to
+ * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the kernel.
+ * 'seq' has been changed from long to int so that it's the same size
+ * on 64-bit kernels as on 32-bit ones.
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_uid_t cuid;
+ __kernel_gid_t cgid;
+#if __BITS_PER_LONG != 64
+ unsigned short int __pad1;
+#endif
+ __kernel_mode_t mode;
+ unsigned short int __pad2;
+ unsigned short int seq;
+ unsigned int __pad3;
+ unsigned long long int __unused1;
+ unsigned long long int __unused2;
+};
+#endif /* __hppa__ */
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+#define HAVE_IPC64_PERM
+/*
+ * The ipc64_perm structure for the powerpc is identical to
+ * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the
+ * kernel. Note extra padding because this structure is passed back
+ * and forth between kernel and user space. Pad space is left for:
+ * - 1 32-bit value to fill up for 8-byte alignment
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_uid_t cuid;
+ __kernel_gid_t cgid;
+ __kernel_mode_t mode;
+ unsigned int seq;
+ unsigned int __pad1;
+ unsigned long long __unused1;
+ unsigned long long __unused2;
+};
+
+#endif /* defined(__powerpc__) || defined(__powerpc64__) */
+
+#if defined(__s390__)
+#define HAVE_IPC64_PERM
+/*
+ * The user_ipc_perm structure for S/390 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+ __kernel_mode_t mode;
+ unsigned short __pad1;
+ unsigned short seq;
+#ifndef __s390x__
+ unsigned short __pad2;
+#endif /* ! __s390x__ */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* defined(__powerpc__) || defined(__powerpc64__) */
+
+#if defined(__sparc__)
+#define HAVE_IPC64_PERM
+/*
+ * The ipc64_perm structure for sparc/sparc64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit seq
+ * - on sparc for 32 bit mode (it is 32 bit on sparc64)
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+#ifndef __arch64__
+ unsigned short __pad0;
+#endif
+ __kernel_mode_t mode;
+ unsigned short __pad1;
+ unsigned short seq;
+ unsigned long long __unused1;
+ unsigned long long __unused2;
+};
+
+#endif /* __sparc__ */
+
+#if defined(__xtensa__)
+#define HAVE_IPC64_PERM
+/*
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of
+ * this archive for more details.
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+ __kernel_mode_t mode;
+ unsigned long seq;
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* __xtensa__ */
+
+#ifndef HAVE_IPC64_PERM
+/*
+ * The generic ipc64_perm structure:
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * ipc64_perm was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t on architectures that only had 16 bit
+ * - 32-bit seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm {
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+ __kernel_mode_t mode;
+ /* pad if mode_t is u16: */
+ unsigned char __pad1[4 - sizeof(__kernel_mode_t)];
+ unsigned short seq;
+ unsigned short __pad2;
+ __kernel_ulong_t __unused1;
+ __kernel_ulong_t __unused2;
+};
+
+#endif /* ipc64_perm */
+
+#endif /* HAVE_IPC64_PERM */
+
+#endif /* IPCBUF_H */
diff --git a/src/kernel/tests/include/lapi/keyctl.h b/src/kernel/tests/include/lapi/keyctl.h
new file mode 100644
index 0000000..c53876e
--- /dev/null
+++ b/src/kernel/tests/include/lapi/keyctl.h
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef KEYCTL_H__
+#define KEYCTL_H__
+
+#include "config.h"
+
+#if defined(HAVE_KEYUTILS_H) && defined(HAVE_LIBKEYUTILS)
+# include <keyutils.h>
+#else
+# ifdef HAVE_LINUX_KEYCTL_H
+# include <linux/keyctl.h>
+# endif /* HAVE_LINUX_KEYCTL_H */
+
+# include <stdarg.h>
+# include <stdint.h>
+# include "lapi/syscalls.h"
+typedef int32_t key_serial_t;
+
+static inline key_serial_t add_key(const char *type,
+ const char *description,
+ const void *payload,
+ size_t plen,
+ key_serial_t ringid)
+{
+ return tst_syscall(__NR_add_key,
+ type, description, payload, plen, ringid);
+}
+
+static inline key_serial_t request_key(const char *type,
+ const char *description,
+ const char *callout_info,
+ key_serial_t destringid)
+{
+ return tst_syscall(__NR_request_key,
+ type, description, callout_info, destringid);
+}
+
+static inline long keyctl(int cmd, ...)
+{
+ va_list va;
+ unsigned long arg2, arg3, arg4, arg5;
+
+ va_start(va, cmd);
+ arg2 = va_arg(va, unsigned long);
+ arg3 = va_arg(va, unsigned long);
+ arg4 = va_arg(va, unsigned long);
+ arg5 = va_arg(va, unsigned long);
+ va_end(va);
+
+ return tst_syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
+}
+
+static inline key_serial_t keyctl_join_session_keyring(const char *name) {
+ return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
+}
+
+#endif /* defined(HAVE_KEYUTILS_H) && defined(HAVE_LIBKEYUTILS) */
+
+/* special process keyring shortcut IDs */
+#ifndef KEY_SPEC_THREAD_KEYRING
+# define KEY_SPEC_THREAD_KEYRING -1
+#endif
+
+#ifndef KEY_SPEC_PROCESS_KEYRING
+# define KEY_SPEC_PROCESS_KEYRING -2
+#endif
+
+#ifndef KEY_SPEC_SESSION_KEYRING
+# define KEY_SPEC_SESSION_KEYRING -3
+#endif
+
+#ifndef KEY_SPEC_USER_KEYRING
+# define KEY_SPEC_USER_KEYRING -4
+#endif
+
+
+#ifndef KEY_SPEC_USER_SESSION_KEYRING
+# define KEY_SPEC_USER_SESSION_KEYRING -5
+#endif
+
+/* request-key default keyrings */
+#ifndef KEY_REQKEY_DEFL_THREAD_KEYRING
+# define KEY_REQKEY_DEFL_THREAD_KEYRING 1
+#endif
+
+#ifndef KEY_REQKEY_DEFL_SESSION_KEYRING
+# define KEY_REQKEY_DEFL_SESSION_KEYRING 3
+#endif
+
+#ifndef KEY_REQKEY_DEFL_DEFAULT
+# define KEY_REQKEY_DEFL_DEFAULT 0
+#endif
+
+/* keyctl commands */
+#ifndef KEYCTL_GET_KEYRING_ID
+# define KEYCTL_GET_KEYRING_ID 0
+#endif
+
+#ifndef KEYCTL_JOIN_SESSION_KEYRING
+# define KEYCTL_JOIN_SESSION_KEYRING 1
+#endif
+
+#ifndef KEYCTL_UPDATE
+# define KEYCTL_UPDATE 2
+#endif
+
+#ifndef KEYCTL_REVOKE
+# define KEYCTL_REVOKE 3
+#endif
+
+#ifndef KEYCTL_SETPERM
+# define KEYCTL_SETPERM 5
+#endif
+
+#ifndef KEYCTL_CLEAR
+# define KEYCTL_CLEAR 7
+#endif
+
+#ifndef KEYCTL_UNLINK
+# define KEYCTL_UNLINK 9
+#endif
+
+#ifndef KEYCTL_READ
+# define KEYCTL_READ 11
+#endif
+
+#ifndef KEYCTL_SET_REQKEY_KEYRING
+# define KEYCTL_SET_REQKEY_KEYRING 14
+#endif
+
+#ifndef KEYCTL_SET_TIMEOUT
+# define KEYCTL_SET_TIMEOUT 15
+#endif
+
+#ifndef KEYCTL_INVALIDATE
+# define KEYCTL_INVALIDATE 21
+#endif
+
+/* key permissions */
+#ifndef KEY_POS_VIEW
+# define KEY_POS_VIEW 0x01000000
+# define KEY_POS_READ 0x02000000
+# define KEY_POS_WRITE 0x04000000
+# define KEY_POS_SEARCH 0x08000000
+# define KEY_POS_LINK 0x10000000
+# define KEY_POS_SETATTR 0x20000000
+# define KEY_POS_ALL 0x3f000000
+
+# define KEY_USR_VIEW 0x00010000
+# define KEY_USR_READ 0x00020000
+# define KEY_USR_WRITE 0x00040000
+# define KEY_USR_SEARCH 0x00080000
+# define KEY_USR_LINK 0x00100000
+# define KEY_USR_SETATTR 0x00200000
+# define KEY_USR_ALL 0x003f0000
+
+# define KEY_GRP_VIEW 0x00000100
+# define KEY_GRP_READ 0x00000200
+# define KEY_GRP_WRITE 0x00000400
+# define KEY_GRP_SEARCH 0x00000800
+# define KEY_GRP_LINK 0x00001000
+# define KEY_GRP_SETATTR 0x00002000
+# define KEY_GRP_ALL 0x00003f00
+
+# define KEY_OTH_VIEW 0x00000001
+# define KEY_OTH_READ 0x00000002
+# define KEY_OTH_WRITE 0x00000004
+# define KEY_OTH_SEARCH 0x00000008
+# define KEY_OTH_LINK 0x00000010
+# define KEY_OTH_SETATTR 0x00000020
+# define KEY_OTH_ALL 0x0000003f
+#endif /* !KEY_POS_VIEW */
+
+#endif /* KEYCTL_H__ */
diff --git a/src/kernel/tests/include/lapi/membarrier.h b/src/kernel/tests/include/lapi/membarrier.h
new file mode 100644
index 0000000..2b6c57f
--- /dev/null
+++ b/src/kernel/tests/include/lapi/membarrier.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#ifndef LAPI_MEMBARRIER_H
+#define LAPI_MEMBARRIER_H
+
+/*
+ * Having <linux/membarrier.h> is enough to know if the test should run or
+ * not, but it might not define all needed MEMBARRIER_CMD_* being tested,
+ * since its first versions included just a few commands.
+ */
+
+enum membarrier_cmd {
+ MEMBARRIER_CMD_QUERY = 0,
+ MEMBARRIER_CMD_GLOBAL = (1 << 0),
+ MEMBARRIER_CMD_GLOBAL_EXPEDITED = (1 << 1),
+ MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = (1 << 2),
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3),
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4),
+ MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5),
+ MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6),
+
+ /* Alias for header backward compatibility. */
+ MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL,
+};
+
+#endif
diff --git a/src/kernel/tests/include/lapi/memfd.h b/src/kernel/tests/include/lapi/memfd.h
new file mode 100644
index 0000000..e38e671
--- /dev/null
+++ b/src/kernel/tests/include/lapi/memfd.h
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ */
+
+#ifndef LAPI_MEMFD_H
+#define LAPI_MEMFD_H
+
+/* flags for memfd_create(2) (unsigned int) */
+#ifndef MFD_CLOEXEC
+# define MFD_CLOEXEC 0x0001U
+#endif
+#ifndef MFD_ALLOW_SEALING
+# define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+/* flags for memfd_create(3) and memfd_create(4) */
+#ifndef MFD_HUGETLB
+#define MFD_HUGETLB 0x0004U
+#endif
+
+#ifndef MFD_HUGE_64KB
+#define MFD_HUGE_64KB (16 << 26)
+#endif
+#ifndef MFD_HUGE_512KB
+#define MFD_HUGE_512KB (19 << 26)
+#endif
+#ifndef MFD_HUGE_2MB
+#define MFD_HUGE_2MB (21 << 26)
+#endif
+#ifndef MFD_HUGE_8MB
+#define MFD_HUGE_8MB (23 << 26)
+#endif
+#ifndef MFD_HUGE_16MB
+#define MFD_HUGE_16MB (24 << 26)
+#endif
+#ifndef MFD_HUGE_256MB
+#define MFD_HUGE_256MB (28 << 26)
+#endif
+#ifndef MFD_HUGE_1GB
+#define MFD_HUGE_1GB (30 << 26)
+#endif
+#ifndef MFD_HUGE_2GB
+#define MFD_HUGE_2GB (31 << 26)
+#endif
+#ifndef MFD_HUGE_16GB
+#define MFD_HUGE_16GB (34 << 26)
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/mkdirat.h b/src/kernel/tests/include/lapi/mkdirat.h
new file mode 100644
index 0000000..bb8c6d8
--- /dev/null
+++ b/src/kernel/tests/include/lapi/mkdirat.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef __MKDIRAT_H__
+#define __MKDIRAT_H__
+
+#include "config.h"
+#include "lapi/syscalls.h"
+#include "lapi/fcntl.h"
+
+#ifndef HAVE_MKDIRAT
+int mkdirat(int dirfd, const char *dirname, int mode)
+{
+ return ltp_syscall(__NR_mkdirat, dirfd, dirname, mode);
+}
+#endif
+
+#endif /* __MKDIRAT_H__ */
diff --git a/src/kernel/tests/include/lapi/mlock2.h b/src/kernel/tests/include/lapi/mlock2.h
new file mode 100644
index 0000000..fa2b2de
--- /dev/null
+++ b/src/kernel/tests/include/lapi/mlock2.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef LAPI_MLOCK2_H__
+# define LAPI_MLOCK2_H__
+
+#include <linux/mman.h>
+
+#ifndef MLOCK_ONFAULT
+# define MLOCK_ONFAULT 0x01
+#endif
+
+#endif /* LAPI_MLOCK2_H__ */
diff --git a/src/kernel/tests/include/lapi/mmap.h b/src/kernel/tests/include/lapi/mmap.h
new file mode 100644
index 0000000..12845b7
--- /dev/null
+++ b/src/kernel/tests/include/lapi/mmap.h
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Fujitsu Ltd.
+ * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
+ */
+
+#ifndef LAPI_MMAP_H__
+#define LAPI_MMAP_H__
+
+#include "config.h"
+
+#ifndef MAP_HUGETLB
+# define MAP_HUGETLB 0x40000
+#endif
+
+#ifndef MADV_REMOVE
+# define MADV_REMOVE 9
+#endif
+
+#ifndef MADV_DONTFORK
+# define MADV_DONTFORK 10
+#endif
+
+#ifndef MADV_DOFORK
+# define MADV_DOFORK 11
+#endif
+
+#ifndef MADV_HWPOISON
+# define MADV_HWPOISON 100
+#endif
+
+#ifndef MADV_SOFT_OFFLINE
+# define MADV_SOFT_OFFLINE 101
+#endif
+
+#ifndef MADV_MERGEABLE
+# define MADV_MERGEABLE 12
+#endif
+
+#ifndef MADV_UNMERGEABLE
+# define MADV_UNMERGEABLE 13
+#endif
+
+#ifndef MADV_HUGEPAGE
+# define MADV_HUGEPAGE 14
+#endif
+
+#ifndef MADV_NOHUGEPAGE
+# define MADV_NOHUGEPAGE 15
+#endif
+
+#ifndef MADV_DONTDUMP
+# define MADV_DONTDUMP 16
+#endif
+
+#ifndef MADV_DODUMP
+# define MADV_DODUMP 17
+#endif
+
+#ifndef MADV_FREE
+# define MADV_FREE 8
+#endif
+
+#ifndef MADV_WIPEONFORK
+# define MADV_WIPEONFORK 18
+# define MADV_KEEPONFORK 19
+#endif
+
+#ifndef MAP_FIXED_NOREPLACE
+
+#ifdef __alpha__
+# define MAP_FIXED_NOREPLACE 0x200000
+#else
+# define MAP_FIXED_NOREPLACE 0x100000
+#endif
+
+#endif /* MAP_FIXED_NOREPLACE */
+
+#ifdef HAVE_SYS_SHM_H
+# include <sys/shm.h>
+# define MMAP_GRANULARITY SHMLBA
+#else
+# include <unistd.h>
+# define MMAP_GRANULARITY getpagesize()
+#endif /* HAVE_SYS_SHM_H */
+
+#endif /* LAPI_MMAP_H__ */
diff --git a/src/kernel/tests/include/lapi/mount.h b/src/kernel/tests/include/lapi/mount.h
new file mode 100644
index 0000000..b8ae1f5
--- /dev/null
+++ b/src/kernel/tests/include/lapi/mount.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Cui Bixuan <cuibixuan@huawei.com>
+ */
+
+#ifndef __MOUNT_H__
+#define __MOUNT_H__
+
+#ifndef MS_REC
+#define MS_REC 16384
+#endif
+
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18)
+#endif
+
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME (1 << 24)
+#endif
+
+#ifndef MNT_DETACH
+#define MNT_DETACH 2
+#endif
+
+#ifndef MNT_EXPIRE
+#define MNT_EXPIRE 4
+#endif
+
+#ifndef UMOUNT_NOFOLLOW
+#define UMOUNT_NOFOLLOW 8
+#endif
+
+#endif /* __MOUNT_H__ */
diff --git a/src/kernel/tests/include/lapi/msg.h b/src/kernel/tests/include/lapi/msg.h
new file mode 100644
index 0000000..d649f33
--- /dev/null
+++ b/src/kernel/tests/include/lapi/msg.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+#ifndef LAPI_MSG_H
+#define LAPI_MSG_H
+
+#include <sys/msg.h>
+
+#ifndef MSG_COPY
+# define MSG_COPY 040000 /* copy (not remove) all queue messages */
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/msgbuf.h b/src/kernel/tests/include/lapi/msgbuf.h
new file mode 100644
index 0000000..f327727
--- /dev/null
+++ b/src/kernel/tests/include/lapi/msgbuf.h
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef IPC_MSGBUF_H
+#define IPC_MSGBUF_H
+
+#include "lapi/posix_types.h"
+#include <sys/sem.h>
+#include "tst_timer.h"
+#include "ipcbuf.h"
+
+#ifndef HAVE_MSQID64_DS
+
+#if defined(__mips__)
+#define HAVE_MSQID64_DS
+
+#if defined(__arch64__)
+/*
+ * The msqid64_ds structure for the MIPS architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous unsigned long values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#elif defined (__MIPSEB__)
+#define HAVE_MSQID64_DS_TIME_HIGH
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#elif defined (__MIPSEL__)
+#define HAVE_MSQID64_DS_TIME_HIGH
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_stime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_ctime; /* last change time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#endif
+
+#endif /* __mips__ */
+
+#if defined(__hppa__)
+#define HAVE_MSQID64_DS
+/*
+ * The msqid64_ds structure for parisc architecture, copied from sparc.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#if __BITS_PER_LONG == 64
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+#else
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* __hppa__ */
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+#define HAVE_MSQID64_DS
+/*
+ * The msqid64_ds structure for the PowerPC architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#ifdef __powerpc64__
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+#else
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* defined(__powerpc__) || defined(__powerpc64__) */
+
+#if defined(__sparc__)
+#define HAVE_MSQID64_DS
+/*
+ * The msqid64_ds structure for sparc64 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#if defined(__arch64__)
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+#else
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* __sparc__ */
+
+#if defined(__x86_64__) && defined(__ILP32__)
+#define HAVE_MSQID64_DS
+/*
+ * The msqid64_ds structure for x86 architecture with x32 ABI.
+ *
+ * On x86-32 and x86-64 we can just use the generic definition, but
+ * x32 uses the same binary layout as x86_64, which is differnet
+ * from other 32-bit architectures.
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+ __kernel_long_t msg_stime; /* last msgsnd time */
+ __kernel_long_t msg_rtime; /* last msgrcv time */
+ __kernel_long_t msg_ctime; /* last change time */
+ __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */
+ __kernel_ulong_t msg_qnum; /* number of messages in queue */
+ __kernel_ulong_t msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ __kernel_ulong_t __unused4;
+ __kernel_ulong_t __unused5;
+};
+
+#endif /* defined(__x86_64__) && defined(__ILP32__) */
+
+#if defined(__xtensa__)
+#define HAVE_MSQID64_DS
+/*
+ * The msqid64_ds structure for the Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#ifdef __XTENSA_EB__
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+#elif defined(__XTENSA_EL__)
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_stime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_ctime; /* last change time */
+ unsigned long msg_ctime_high;
+#else
+# error processor byte order undefined!
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* __xtensa__ */
+
+#ifndef HAVE_MSQID64_DS
+/*
+ * generic msqid64_ds structure.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * msqid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures use a 64-bit long time field here, while
+ * 32 bit architectures have a pair of unsigned long values.
+ * On big-endian systems, the lower half is in the wrong place.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#if __BITS_PER_LONG == 64
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+#else
+#define HAVE_MSQID64_DS_TIME_HIGH
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_stime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_ctime; /* last change time */
+ unsigned long msg_ctime_high;
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* msqid64_ds */
+
+#endif /* HAVE_MSQID64_DS */
+
+#endif /* IPC_MSGBUF_H */
diff --git a/src/kernel/tests/include/lapi/namespaces_constants.h b/src/kernel/tests/include/lapi/namespaces_constants.h
new file mode 100644
index 0000000..8f73c43
--- /dev/null
+++ b/src/kernel/tests/include/lapi/namespaces_constants.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Red Hat, Inc.
+ */
+
+#ifndef __NAMESPACES_CONSTANTS_H__
+#define __NAMESPACES_CONSTANTS_H__
+
+#ifndef CLONE_NEWIPC
+# define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWNS
+# define CLONE_NEWNS 0x00020000
+#endif
+#ifndef CLONE_NEWNET
+# define CLONE_NEWNET 0x40000000
+#endif
+#ifndef CLONE_NEWPID
+# define CLONE_NEWPID 0x20000000
+#endif
+#ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWUTS
+# define CLONE_NEWUTS 0x04000000
+#endif
+#ifndef CLONE_NEWTIME
+# define CLONE_NEWTIME 0x00000080
+#endif
+
+#endif /* __NAMESPACES_CONSTANTS_H__ */
diff --git a/src/kernel/tests/include/lapi/netinet_in.h b/src/kernel/tests/include/lapi/netinet_in.h
new file mode 100644
index 0000000..e88485c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/netinet_in.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef LAPI_IN_H__
+#define LAPI_IN_H__
+
+#include <netinet/in.h>
+
+#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif
+
+#ifndef IPPROTO_UDPLITE
+# define IPPROTO_UDPLITE 136 /* UDP-Lite (RFC 3828) */
+#endif
+
+#ifndef IP_BIND_ADDRESS_NO_PORT
+# define IP_BIND_ADDRESS_NO_PORT 24
+#endif
+
+#endif /* LAPI_IN_H__ */
diff --git a/src/kernel/tests/include/lapi/openat2.h b/src/kernel/tests/include/lapi/openat2.h
new file mode 100644
index 0000000..62da1a0
--- /dev/null
+++ b/src/kernel/tests/include/lapi/openat2.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef OPENAT2_H
+#define OPENAT2_H
+
+#include <sys/syscall.h>
+#include <linux/types.h>
+
+#include "lapi/syscalls.h"
+
+#include "config.h"
+
+#ifndef HAVE_OPENAT2
+/*
+ * Arguments for how openat2(2) should open the target path. If only @flags and
+ * @mode are non-zero, then openat2(2) operates very similarly to openat(2).
+ *
+ * However, unlike openat(2), unknown or invalid bits in @flags result in
+ * -EINVAL rather than being silently ignored. @mode must be zero unless one of
+ * {O_CREAT, O_TMPFILE} are set.
+ *
+ * @flags: O_* flags.
+ * @mode: O_CREAT/O_TMPFILE file mode.
+ * @resolve: RESOLVE_* flags.
+ */
+struct open_how {
+ uint64_t flags;
+ uint64_t mode;
+ uint64_t resolve;
+};
+
+/* how->resolve flags for openat2(2). */
+#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
+ (includes bind-mounts). */
+#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
+ "magic-links". */
+#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
+ (implies OEXT_NO_MAGICLINKS) */
+#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
+ "..", symlinks, and absolute
+ paths which escape the dirfd. */
+#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
+ be scoped inside the dirfd
+ (similar to chroot(2)). */
+
+int openat2(int dfd, const char *pathname, struct open_how *how, size_t size)
+{
+ return tst_syscall(__NR_openat2, dfd, pathname, how, size);
+}
+#endif
+
+struct open_how_pad {
+ /* how should be kept as the first entry here */
+ struct open_how how;
+ uint64_t pad;
+};
+
+void openat2_supported_by_kernel(void)
+{
+ if ((tst_kvercmp(5, 6, 0)) < 0) {
+ /* Check if the syscall is backported on an older kernel */
+ TEST(syscall(__NR_openat2, -1, NULL, NULL, 0));
+ if (TST_RET == -1 && TST_ERR == ENOSYS)
+ tst_brk(TCONF, "Test not supported on kernel version < v5.6");
+ }
+}
+
+#endif /* OPENAT2_H */
diff --git a/src/kernel/tests/include/lapi/personality.h b/src/kernel/tests/include/lapi/personality.h
new file mode 100644
index 0000000..6b4b7eb
--- /dev/null
+++ b/src/kernel/tests/include/lapi/personality.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+/* In the Linux kernel and glibc enums are (mostly) used for the constants,
+ * but in musl macros are used.
+ */
+
+#ifndef PERSONALITY_H
+#define PERSONALITY_H
+
+#include <sys/personality.h>
+
+#ifndef UNAME26
+# define UNAME26 0x0020000
+#endif
+
+#ifndef READ_IMPLIES_EXEC
+# define READ_IMPLIES_EXEC 0x0400000
+#endif
+
+#endif /* PERSONALITY_H */
diff --git a/src/kernel/tests/include/lapi/pidfd_open.h b/src/kernel/tests/include/lapi/pidfd_open.h
new file mode 100644
index 0000000..9f532f8
--- /dev/null
+++ b/src/kernel/tests/include/lapi/pidfd_open.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef PIDFD_OPEN_H
+#define PIDFD_OPEN_H
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+#include "lapi/syscalls.h"
+
+#include "config.h"
+
+#ifndef HAVE_PIDFD_OPEN
+int pidfd_open(pid_t pid, unsigned int flags)
+{
+ return tst_syscall(__NR_pidfd_open, pid, flags);
+}
+#endif
+
+#endif /* PIDFD_OPEN_H */
diff --git a/src/kernel/tests/include/lapi/pidfd_send_signal.h b/src/kernel/tests/include/lapi/pidfd_send_signal.h
new file mode 100644
index 0000000..8352d2a
--- /dev/null
+++ b/src/kernel/tests/include/lapi/pidfd_send_signal.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 SUSE LLC
+ * Author: Christian Amann <camann@suse.com>
+ */
+
+#ifndef PIDFD_SEND_SIGNAL_H
+#define PIDFD_SEND_SIGNAL_H
+
+#include "tst_test.h"
+#include "lapi/syscalls.h"
+
+static inline void pidfd_send_signal_supported(void)
+{
+ /* allow the tests to fail early */
+ tst_syscall(__NR_pidfd_send_signal);
+}
+
+#ifndef HAVE_PIDFD_SEND_SIGNAL
+static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
+ unsigned int flags)
+{
+ return tst_syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
+}
+#endif /* HAVE_PIDFD_SEND_SIGNAL */
+
+#endif /* PIDFD_SEND_SIGNAL_H */
diff --git a/src/kernel/tests/include/lapi/posix_clocks.h b/src/kernel/tests/include/lapi/posix_clocks.h
new file mode 100644
index 0000000..ae2139f
--- /dev/null
+++ b/src/kernel/tests/include/lapi/posix_clocks.h
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linux Test Project
+ * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <time.h>
+
+#ifndef POSIX_CLOCKS_H__
+#define POSIX_CLOCKS_H__
+
+#define MAX_CLOCKS 16
+
+#ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW 4
+#endif
+
+#ifndef CLOCK_REALTIME_COARSE
+# define CLOCK_REALTIME_COARSE 5
+#endif
+
+#ifndef CLOCK_MONOTONIC_COARSE
+# define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+#ifndef CLOCK_BOOTTIME
+# define CLOCK_BOOTTIME 7
+#endif
+
+#ifndef CLOCK_REALTIME_ALARM
+# define CLOCK_REALTIME_ALARM 8
+#endif
+
+#ifndef CLOCK_BOOTTIME_ALARM
+# define CLOCK_BOOTTIME_ALARM 9
+#endif
+
+#ifndef CLOCK_TAI
+#define CLOCK_TAI 11
+#endif
+
+#endif /* POSIX_CLOCKS_H__ */
diff --git a/src/kernel/tests/include/lapi/posix_types.h b/src/kernel/tests/include/lapi/posix_types.h
new file mode 100644
index 0000000..9c0947c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/posix_types.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Linux Test Project, 2014-2019
+ */
+
+#ifndef POSIX_TYPES_H__
+#define POSIX_TYPES_H__
+
+#include <linux/posix_types.h>
+
+#ifndef __kernel_long_t
+# if defined(__x86_64__) && defined(__ILP32__)
+typedef long long __kernel_long_t;
+typedef unsigned long long __kernel_ulong_t;
+# else
+typedef long __kernel_long_t;
+typedef unsigned long __kernel_ulong_t;
+# endif
+#endif
+
+#endif /* POSIX_TYPES_H__ */
diff --git a/src/kernel/tests/include/lapi/prctl.h b/src/kernel/tests/include/lapi/prctl.h
new file mode 100644
index 0000000..4499df0
--- /dev/null
+++ b/src/kernel/tests/include/lapi/prctl.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef LAPI_PRCTL_H__
+# define LAPI_PRCTL_H__
+
+#include <sys/prctl.h>
+
+#ifndef PR_SET_NAME
+# define PR_SET_NAME 15
+# define PR_GET_NAME 16
+#endif
+
+#ifndef PR_SET_SECCOMP
+# define PR_GET_SECCOMP 21
+# define PR_SET_SECCOMP 22
+#endif
+
+#ifndef PR_SET_TIMERSLACK
+# define PR_SET_TIMERSLACK 29
+# define PR_GET_TIMERSLACK 30
+#endif
+
+#ifndef PR_SET_CHILD_SUBREAPER
+# define PR_SET_CHILD_SUBREAPER 36
+# define PR_GET_CHILD_SUBREAPER 37
+#endif
+
+#ifndef PR_SET_NO_NEW_PRIVS
+# define PR_SET_NO_NEW_PRIVS 38
+# define PR_GET_NO_NEW_PRIVS 39
+#endif
+
+#ifndef PR_SET_THP_DISABLE
+# define PR_SET_THP_DISABLE 41
+# define PR_GET_THP_DISABLE 42
+#endif
+
+#ifndef PR_CAP_AMBIENT
+# define PR_CAP_AMBIENT 47
+# define PR_CAP_AMBIENT_IS_SET 1
+# define PR_CAP_AMBIENT_RAISE 2
+# define PR_CAP_AMBIENT_LOWER 3
+# define PR_CAP_AMBIENT_CLEAR_ALL 4
+#endif
+
+#ifndef PR_GET_SPECULATION_CTRL
+# define PR_GET_SPECULATION_CTRL 52
+# define PR_SET_SPECULATION_CTRL 53
+#endif
+
+#endif /* LAPI_PRCTL_H__ */
diff --git a/src/kernel/tests/include/lapi/preadv2.h b/src/kernel/tests/include/lapi/preadv2.h
new file mode 100644
index 0000000..538ed72
--- /dev/null
+++ b/src/kernel/tests/include/lapi/preadv2.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef PREADV2_H
+#define PREADV2_H
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifndef RWF_NOWAIT
+# define RWF_NOWAIT 0x00000008
+#endif
+
+#if !defined(HAVE_PREADV2)
+
+/* LO_HI_LONG taken from glibc */
+# define LO_HI_LONG(val) (long) (val), (long) (((uint64_t) (val)) >> 32)
+
+ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset,
+ int flags)
+{
+ return tst_syscall(__NR_preadv2, fd, iov, iovcnt,
+ LO_HI_LONG(offset), flags);
+}
+#endif
+
+#endif /* PREADV2_H */
diff --git a/src/kernel/tests/include/lapi/pwritev2.h b/src/kernel/tests/include/lapi/pwritev2.h
new file mode 100644
index 0000000..305e48e
--- /dev/null
+++ b/src/kernel/tests/include/lapi/pwritev2.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Jinhui Huang <huangjh.jy@cn.fujitsu.com>
+ */
+
+#ifndef PWRITEV2_H
+#define PWRITEV2_H
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_PWRITEV2)
+
+/* LO_HI_LONG taken from glibc */
+# define LO_HI_LONG(val) (long) (val), (long) (((uint64_t) (val)) >> 32)
+
+ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset,
+ int flags)
+{
+ return tst_syscall(__NR_pwritev2, fd, iov, iovcnt,
+ LO_HI_LONG(offset), flags);
+}
+#endif
+
+#endif /* PWRITEV2_H */
diff --git a/src/kernel/tests/include/lapi/quotactl.h b/src/kernel/tests/include/lapi/quotactl.h
new file mode 100644
index 0000000..c1ec9d6
--- /dev/null
+++ b/src/kernel/tests/include/lapi/quotactl.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2019 Fujitsu Ltd.
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ */
+
+#ifndef LAPI_QUOTACTL_H__
+#define LAPI_QUOTACTL_H__
+
+#include <sys/quota.h>
+
+#ifdef HAVE_STRUCT_IF_NEXTDQBLK
+# include <linux/quota.h>
+#else
+# include <stdint.h>
+struct if_nextdqblk {
+ uint64_t dqb_bhardlimit;
+ uint64_t dqb_bsoftlimit;
+ uint64_t dqb_curspace;
+ uint64_t dqb_ihardlimit;
+ uint64_t dqb_isoftlimit;
+ uint64_t dqb_curinodes;
+ uint64_t dqb_btime;
+ uint64_t dqb_itime;
+ uint32_t dqb_valid;
+ uint32_t dqb_id;
+};
+#endif /* HAVE_STRUCT_IF_NEXTDQBLK */
+
+#ifndef HAVE_STRUCT_FS_QUOTA_STATV
+# include <stdint.h>
+struct fs_qfilestatv {
+ uint64_t qfs_ino;
+ uint64_t qfs_nblks;
+ uint32_t qfs_nextents;
+ uint32_t qfs_pad;
+};
+
+struct fs_quota_statv {
+ int8_t qs_version;
+ uint8_t qs_pad1;
+ uint16_t qs_flags;
+ uint32_t qs_incoredqs;
+ struct fs_qfilestatv qs_uquota;
+ struct fs_qfilestatv qs_gquota;
+ struct fs_qfilestatv qs_pquota;
+ int32_t qs_btimelimit;
+ int32_t qs_itimelimit;
+ int32_t qs_rtbtimelimit;
+ uint16_t qs_bwarnlimit;
+ uint16_t qs_iwarnlimit;
+ uint64_t qs_pad2[8];
+};
+# define FS_QSTATV_VERSION1 1
+#endif /* HAVE_STRUCT_FS_QUOTA_STATV */
+
+#ifndef PRJQUOTA
+# define PRJQUOTA 2
+#endif
+
+#ifndef Q_XQUOTARM
+# define Q_XQUOTARM XQM_CMD(6)
+#endif
+
+#ifndef Q_XGETQSTATV
+# define Q_XGETQSTATV XQM_CMD(8)
+#endif
+
+#ifndef Q_XGETNEXTQUOTA
+# define Q_XGETNEXTQUOTA XQM_CMD(9)
+#endif
+
+#ifndef Q_GETNEXTQUOTA
+# define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */
+#endif
+
+#endif /* LAPI_QUOTACTL_H__ */
diff --git a/src/kernel/tests/include/lapi/readdir.h b/src/kernel/tests/include/lapi/readdir.h
new file mode 100644
index 0000000..84e77ae
--- /dev/null
+++ b/src/kernel/tests/include/lapi/readdir.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Fujitsu Ltd.
+ * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
+ */
+
+#ifndef READDIR_H
+#define READDIR_H
+
+#include <limits.h>
+
+struct old_linux_dirent {
+ long d_ino; /* inode number */
+ off_t d_off; /* offset to this old_linux_dirent */
+ unsigned short d_reclen; /* length of this d_name */
+ char d_name[NAME_MAX+1]; /* filename (null-terminated) */
+};
+
+#endif /* READDIR_H */
diff --git a/src/kernel/tests/include/lapi/readlinkat.h b/src/kernel/tests/include/lapi/readlinkat.h
new file mode 100644
index 0000000..5a3a7b2
--- /dev/null
+++ b/src/kernel/tests/include/lapi/readlinkat.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef __READLINKAT_H__
+#define __READLINKAT_H__
+
+#include "config.h"
+#include "lapi/syscalls.h"
+#include "lapi/fcntl.h"
+
+#ifndef HAVE_READLINKAT
+int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+ return ltp_syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz);
+}
+#endif
+
+#endif /* __READLINKAT_H__ */
diff --git a/src/kernel/tests/include/lapi/renameat.h b/src/kernel/tests/include/lapi/renameat.h
new file mode 100644
index 0000000..66d3e21
--- /dev/null
+++ b/src/kernel/tests/include/lapi/renameat.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ */
+
+#ifndef RENAMEAT_H
+#define RENAMEAT_H
+
+#include <sys/types.h>
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_RENAMEAT)
+int renameat(int olddirfd, const char *oldpath, int newdirfd,
+ const char *newpath)
+{
+ return ltp_syscall(__NR_renameat, olddirfd, oldpath, newdirfd,
+ newpath);
+}
+#endif
+
+#endif /* RENAMEAT_H */
diff --git a/src/kernel/tests/include/lapi/rt_sigaction.h b/src/kernel/tests/include/lapi/rt_sigaction.h
new file mode 100644
index 0000000..3af9136
--- /dev/null
+++ b/src/kernel/tests/include/lapi/rt_sigaction.h
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved.
+ * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved.
+ * Author: Liu Bo <liubo2009@cn.fujitsu.com>
+ * Author: Ngie Cooper <yaneurabeya@gmail.com>
+ */
+
+#ifndef LTP_RT_SIGACTION_H
+#define LTP_RT_SIGACTION_H
+
+#include "ltp_signal.h"
+
+#define INVAL_SA_PTR ((void *)-1)
+
+#if defined(__mips__)
+struct kernel_sigaction {
+ unsigned int sa_flags;
+ void (* k_sa_handler)(int);
+ sigset_t sa_mask;
+};
+#else
+struct kernel_sigaction {
+ void (* k_sa_handler)(int);
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+ sigset_t sa_mask;
+};
+#endif
+
+/* This macro marks if (struct sigaction) has .sa_restorer member */
+#if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__)
+# define HAVE_SA_RESTORER
+#endif
+
+#ifdef __x86_64__
+
+/*
+ * From asm/signal.h -- this value isn't exported anywhere outside of glibc and
+ * asm/signal.h and is only required for the rt_sig* function family because
+ * sigaction(2), et all, appends this if necessary to
+ * (struct sigaction).sa_flags. HEH.
+ *
+ * I do #undef though, just in case...
+ *
+ * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or
+ * other):
+ *
+ * x86-64 should always use SA_RESTORER.
+ *
+ * -- thus SA_RESTORER must always be defined along with
+ * (struct sigaction).sa_restorer for this architecture.
+ */
+#undef SA_RESTORER
+#define SA_RESTORER 0x04000000
+
+void (*restore_rt)(void);
+
+static void handler_h(int signal)
+{
+ return;
+}
+
+/* Setup an initial signal handler for signal number = sig for x86_64. */
+static inline int sig_initial(int sig)
+{
+ int ret_code = -1;
+ struct sigaction act, oact;
+
+ act.sa_handler = handler_h;
+ act.sa_flags = 0;
+ /* Clear out the signal set. */
+ if (sigemptyset(&act.sa_mask) < 0) {
+ /* Add the signal to the mask set. */
+ } else if (sigaddset(&act.sa_mask, sig) < 0) {
+ /* Set act.sa_restorer via syscall(2) */
+ } else if (sigaction(sig, &act, &oact) < 0) {
+ /* Copy oact.sa_restorer via syscall(2) */
+ } else if (sigaction(sig, &act, &oact) < 0) {
+ /* And voila -- we just tricked the kernel into giving us our
+ * restorer function! */
+ } else {
+ restore_rt = oact.sa_restorer;
+ ret_code = 0;
+ }
+
+ return ret_code;
+}
+
+#endif /* __x86_64__ */
+
+#ifdef __sparc__
+# if defined __arch64__ || defined __sparcv9
+
+/*
+ * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
+ */
+
+extern char *__rt_sig_stub;
+
+static void __attribute__((used)) __rt_sigreturn_stub(void)
+{
+ __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
+ "ta 0x6d\n\t"
+ : /* no outputs */
+ : "i" (__NR_rt_sigreturn));
+}
+
+# else /* sparc32 */
+
+/*
+ * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
+ */
+
+extern char *__rt_sig_stub, *__sig_stub;
+
+static void __attribute__((used)) __rt_sigreturn_stub(void)
+{
+ __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t"
+ "ta 0x10\n\t"
+ : /* no outputs */
+ : "i" (__NR_rt_sigreturn));
+}
+
+static void __attribute__((used)) __sigreturn_stub(void)
+{
+ __asm__ ("__sig_stub: mov %0, %%g1\n\t"
+ "ta 0x10\n\t"
+ : /* no outputs */
+ : "i" (__NR_sigreturn));
+}
+
+# endif
+#endif /* __sparc__ */
+
+#ifdef __arc__
+
+#undef SA_RESTORER
+#define SA_RESTORER 0x04000000
+
+/*
+ * based on uClibc/libc/sysdeps/linux/arc/sigaction.c
+ */
+static void
+__attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void)
+{
+ __asm__ (
+ "mov r8, %0 \n\t"
+#ifdef __ARCHS__
+ "trap_s 0 \n\t"
+#else
+ "trap0 \n\t"
+#endif
+ : /* no outputs */
+ : "i" (__NR_rt_sigreturn)
+ : "r8");
+}
+#endif
+
+#ifdef TST_TEST_H__
+# define TST_SYSCALL tst_syscall
+#else
+# define TST_SYSCALL ltp_syscall
+#endif
+
+/* This is a wrapper for __NR_rt_sigaction syscall.
+ * act/oact values of INVAL_SA_PTR is used to pass
+ * an invalid pointer to syscall(__NR_rt_sigaction)
+ *
+ * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c
+ */
+
+static int ltp_rt_sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oact, size_t sigsetsize)
+{
+ int ret;
+ struct kernel_sigaction kact, koact;
+ struct kernel_sigaction *kact_p = NULL;
+ struct kernel_sigaction *koact_p = NULL;
+
+ if (act == INVAL_SA_PTR) {
+ kact_p = INVAL_SA_PTR;
+ } else if (act) {
+ kact.k_sa_handler = act->sa_handler;
+ memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t));
+ kact.sa_flags = act->sa_flags;
+#ifndef __mips__
+ kact.sa_restorer = NULL;
+#endif
+ kact_p = &kact;
+ }
+
+ if (oact == INVAL_SA_PTR)
+ koact_p = INVAL_SA_PTR;
+ else if (oact)
+ koact_p = &koact;
+
+#ifdef __x86_64__
+ sig_initial(signum);
+#endif
+
+#if defined __x86_64__ || defined __arc__
+ kact.sa_flags |= SA_RESTORER;
+ kact.sa_restorer = restore_rt;
+#endif
+
+#ifdef __sparc__
+ unsigned long stub = 0;
+# if defined __arch64__ || defined __sparcv9
+ stub = ((unsigned long) &__rt_sig_stub) - 8;
+# else /* sparc32 */
+ if ((kact.sa_flags & SA_SIGINFO) != 0)
+ stub = ((unsigned long) &__rt_sig_stub) - 8;
+ else
+ stub = ((unsigned long) &__sig_stub) - 8;
+# endif
+#endif
+
+
+#ifdef __sparc__
+ ret = TST_SYSCALL(__NR_rt_sigaction, signum,
+ kact_p, koact_p,
+ stub, sigsetsize);
+#else
+ ret = TST_SYSCALL(__NR_rt_sigaction, signum,
+ kact_p, koact_p,
+ sigsetsize);
+#endif
+
+ if (ret >= 0) {
+ if (oact && (oact != INVAL_SA_PTR)) {
+ oact->sa_handler = koact.k_sa_handler;
+ memcpy(&oact->sa_mask, &koact.sa_mask,
+ sizeof(sigset_t));
+ oact->sa_flags = koact.sa_flags;
+#ifdef HAVE_SA_RESTORER
+ oact->sa_restorer = koact.sa_restorer;
+#endif
+ }
+ }
+
+ return ret;
+}
+
+#endif /* LTP_RT_SIGACTION_H */
diff --git a/src/kernel/tests/include/lapi/safe_rt_signal.h b/src/kernel/tests/include/lapi/safe_rt_signal.h
new file mode 100644
index 0000000..67fa444
--- /dev/null
+++ b/src/kernel/tests/include/lapi/safe_rt_signal.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef SAFE_RT_SIGNAL_H__
+#define SAFE_RT_SIGNAL_H__
+
+#include <signal.h>
+#include "lapi/rt_sigaction.h"
+
+static inline int safe_rt_sigaction(const char *file, const int lineno,
+ int signum, const struct sigaction *act,
+ struct sigaction *oact, size_t sigsetsize)
+{
+ int ret;
+
+ ret = ltp_rt_sigaction(signum, act, oact, sigsetsize);
+ if (ret < 0) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: ltp_rt_sigaction(%i, %p, %p, %zu) failed",
+ file, lineno, signum, act, oact, sigsetsize);
+ }
+
+ return ret;
+}
+
+#define SAFE_RT_SIGACTION(signum, act, oldact, sigsetsize) \
+ safe_rt_sigaction(__FILE__, __LINE__, signum, act, oldact, sigsetsize)
+
+
+static inline int safe_rt_sigprocmask(const char *file, const int lineno,
+ int how, const sigset_t *set,
+ sigset_t *oldset, size_t sigsetsize)
+{
+ int ret;
+
+ ret = tst_syscall(__NR_rt_sigprocmask, how, set, oldset, sigsetsize);
+ if (ret < 0) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: rt_sigprocmask(%i, %p, %p, %zu) failed",
+ file, lineno, how, set, oldset, sigsetsize);
+ }
+
+ return ret;
+}
+
+#define SAFE_RT_SIGPROCMASK(how, set, oldset, sigsetsize) \
+ safe_rt_sigprocmask(__FILE__, __LINE__, how, set, oldset, sigsetsize)
+
+#endif /* SAFE_RT_SIGNAL_H__ */
diff --git a/src/kernel/tests/include/lapi/sched.h b/src/kernel/tests/include/lapi/sched.h
new file mode 100644
index 0000000..26fe445
--- /dev/null
+++ b/src/kernel/tests/include/lapi/sched.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Cui Bixuan <cuibixuan@huawei.com>
+ */
+
+#ifndef __SCHED_H__
+#define __SCHED_H__
+
+#include "lapi/syscalls.h"
+#include <stdint.h>
+#include <inttypes.h>
+
+struct sched_attr {
+ uint32_t size;
+
+ uint32_t sched_policy;
+ uint64_t sched_flags;
+
+ /* SCHED_NORMAL, SCHED_BATCH */
+ int32_t sched_nice;
+
+ /* SCHED_FIFO, SCHED_RR */
+ uint32_t sched_priority;
+
+ /* SCHED_DEADLINE (nsec) */
+ uint64_t sched_runtime;
+ uint64_t sched_deadline;
+ uint64_t sched_period;
+};
+
+int sched_setattr(pid_t pid,
+ const struct sched_attr *attr,
+ unsigned int flags)
+{
+ return syscall(__NR_sched_setattr, pid, attr, flags);
+}
+
+int sched_getattr(pid_t pid,
+ struct sched_attr *attr,
+ unsigned int size,
+ unsigned int flags)
+{
+ return syscall(__NR_sched_getattr, pid, attr, size, flags);
+}
+
+#ifndef CLONE_VM
+#define CLONE_VM 0x00000100
+#endif
+
+#ifndef CLONE_FS
+#define CLONE_FS 0x00000200
+#endif
+
+#ifndef CLONE_SYSVSEM
+#define CLONE_SYSVSEM 0x00040000
+#endif
+
+#ifndef CLONE_IO
+#define CLONE_IO 0x80000000
+#endif
+
+#endif /* __SCHED_H__ */
diff --git a/src/kernel/tests/include/lapi/sctp.h b/src/kernel/tests/include/lapi/sctp.h
new file mode 100644
index 0000000..c4c1cc9
--- /dev/null
+++ b/src/kernel/tests/include/lapi/sctp.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Oracle and/or its affiliates.
+ */
+
+#ifndef LAPI_SCTP_H__
+#define LAPI_SCTP_H__
+
+#ifdef HAVE_NETINET_SCTP_H
+# include <netinet/sctp.h>
+#endif
+
+#ifndef SCTP_SOCKOPT_BINDX_ADD
+# define SCTP_SOCKOPT_BINDX_ADD 100
+#endif
+
+#endif /* LAPI_SCTP_H__ */
diff --git a/src/kernel/tests/include/lapi/seccomp.h b/src/kernel/tests/include/lapi/seccomp.h
new file mode 100644
index 0000000..fe95cab
--- /dev/null
+++ b/src/kernel/tests/include/lapi/seccomp.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+#ifndef LAPI_SECCOMP_H
+#define LAPI_SECCOMP_H
+
+#include <stdint.h>
+
+#ifdef HAVE_LINUX_SECCOMP_H
+# include <linux/seccomp.h>
+#else
+/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */
+# define SECCOMP_MODE_DISABLED 0
+# define SECCOMP_MODE_STRICT 1
+# define SECCOMP_MODE_FILTER 2
+
+# define SECCOMP_RET_KILL_THREAD 0x00000000U /* kill the thread */
+# define SECCOMP_RET_KILL SECCOMP_RET_KILL_THREAD
+# define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
+
+/**
+ * struct seccomp_data - the format the BPF program executes over.
+ * @nr: the system call number
+ * @arch: indicates system call convention as an AUDIT_ARCH_* value
+ * as defined in <linux/audit.h>.
+ * @instruction_pointer: at the time of the system call.
+ * @args: up to 6 system call arguments always stored as 64-bit values
+ * regardless of the architecture.
+ */
+struct seccomp_data {
+ int nr;
+ uint32_t arch;
+ uint64_t instruction_pointer;
+ uint64_t args[6];
+};
+
+#endif /* HAVE_LINUX_SECCOMP_H*/
+#endif /* LAPI_SECCOMP_H */
diff --git a/src/kernel/tests/include/lapi/securebits.h b/src/kernel/tests/include/lapi/securebits.h
new file mode 100644
index 0000000..2da137c
--- /dev/null
+++ b/src/kernel/tests/include/lapi/securebits.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+#ifndef LAPI_SECUREBITS_H
+#define LAPI_SECUREBITS_H
+
+# ifdef HAVE_LINUX_SECUREBITS_H
+# include <linux/securebits.h>
+# endif
+
+# ifndef SECBIT_NO_CAP_AMBIENT_RAISE
+# define SECBIT_NO_CAP_AMBIENT_RAISE 6
+# endif
+
+#endif /* LAPI_SECUREBITS_H */
diff --git a/src/kernel/tests/include/lapi/seek.h b/src/kernel/tests/include/lapi/seek.h
new file mode 100644
index 0000000..1a29ba4
--- /dev/null
+++ b/src/kernel/tests/include/lapi/seek.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef SEEK_H__
+#define SEEK_H__
+
+#include <unistd.h>
+
+#ifndef SEEK_DATA
+# define SEEK_DATA 3
+#endif
+
+#ifndef SEEK_HOLE
+# define SEEK_HOLE 4
+#endif
+
+#endif /* SEEK_H__ */
diff --git a/src/kernel/tests/include/lapi/sembuf.h b/src/kernel/tests/include/lapi/sembuf.h
new file mode 100644
index 0000000..4ef0483
--- /dev/null
+++ b/src/kernel/tests/include/lapi/sembuf.h
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef IPC_SEMBUF_H
+#define IPC_SEMBUF_H
+
+#include "lapi/posix_types.h"
+#include <sys/sem.h>
+#include "tst_timer.h"
+#include "ipcbuf.h"
+
+#ifndef HAVE_SEMID64_DS
+
+#if defined(__mips__)
+#define HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for the MIPS architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for 2 miscellaneous 64-bit values on mips64,
+ * but used for the upper 32 bit of the time values on mips32.
+ */
+#if defined(__arch64__)
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+#else
+#define HAVE_SEMID64_DS_TIME_HIGH
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime; /* last change time */
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long sem_otime_high;
+ unsigned long sem_ctime_high;
+};
+#endif
+#endif /* __mips__ */
+
+#if defined(__hppa__)
+#define HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#if __BITS_PER_LONG == 64
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+#else
+#define HAVE_SEMID64_DS_TIME_HIGH
+ unsigned long sem_otime_high;
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime_high;
+ unsigned long sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+#endif /* __hppa__ */
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+#define HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for PPC architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32/64-bit values
+ */
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#ifndef __powerpc64__
+#define HAVE_SEMID64_DS_TIME_HIGH
+ unsigned long sem_otime_high;
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime_high;
+ unsigned long sem_ctime; /* last change time */
+#else
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+#endif /* defined(__powerpc__) || defined(__powerpc64__) */
+
+#if defined(__sparc__)
+#define HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for sparc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#if defined(__arch64__)
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+#else
+#define HAVE_SEMID64_DS_TIME_HIGH
+ unsigned long sem_otime_high;
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime_high;
+ unsigned long sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+#endif /* __sparc__ */
+
+#if defined(__x86_64__)
+#define HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for x86 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ *
+ * x86_64 and x32 incorrectly added padding here, so the structures
+ * are still incompatible with the padding on x86.
+ */
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#ifdef __i386__
+#define HAVE_SEMID64_DS_TIME_HIGH
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_otime_high;
+ unsigned long sem_ctime; /* last change time */
+ unsigned long sem_ctime_high;
+#else
+ __kernel_long_t sem_otime; /* last semop time */
+ __kernel_ulong_t __unused1;
+ __kernel_long_t sem_ctime; /* last change time */
+ __kernel_ulong_t __unused2;
+#endif
+ __kernel_ulong_t sem_nsems; /* no. of semaphores in array */
+ __kernel_ulong_t __unused3;
+ __kernel_ulong_t __unused4;
+};
+#endif /* defined(__x86_64__) */
+
+#if defined(__xtensa__)
+#define HAVE_SEMID64_DS
+#define HAVE_SEMID64_DS_TIME_HIGH
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#ifdef __XTENSA_EL__
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_otime_high;
+ unsigned long sem_ctime; /* last change time */
+ unsigned long sem_ctime_high;
+#else
+ unsigned long sem_otime_high;
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime_high;
+ unsigned long sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* __xtensa__ */
+
+#ifndef HAVE_SEMID64_DS
+/*
+ * The semid64_ds structure for most architectures (though it came
+ * from x86_32 originally). Note extra padding because this structure
+ * is passed back and forth between kernel and user space.
+ *
+ * semid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures use a 64-bit long time field here, while
+ * 32 bit architectures have a pair of unsigned long values.
+ *
+ * On big-endian systems, the padding is in the wrong place for
+ * historic reasons, so user space has to reconstruct a time_t
+ * value using
+ *
+ * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime +
+ * ((long long)kernel_semid64_ds.sem_otime_high << 32)
+ *
+ * Pad space is left for 2 miscellaneous 32-bit values
+ */
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#if __BITS_PER_LONG == 64
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+#else
+#define HAVE_SEMID64_DS_TIME_HIGH
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_otime_high;
+ unsigned long sem_ctime; /* last change time */
+ unsigned long sem_ctime_high;
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+#endif /* semid64_ds */
+
+#endif /* HAVE_SEMID64_DS */
+
+#endif /* IPC_SEMBUF_H */
diff --git a/src/kernel/tests/include/lapi/semun.h b/src/kernel/tests/include/lapi/semun.h
new file mode 100644
index 0000000..1a9dc98
--- /dev/null
+++ b/src/kernel/tests/include/lapi/semun.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015 Linux Test Project
+ */
+
+#ifndef SEMUN_H__
+#define SEMUN_H__
+
+#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short *array; /* array for GETALL, SETALL */
+ /* Linux specific part: */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+#endif
+
+#endif /* SEMUN_H__ */
diff --git a/src/kernel/tests/include/lapi/setns.h b/src/kernel/tests/include/lapi/setns.h
new file mode 100644
index 0000000..7b0a7af
--- /dev/null
+++ b/src/kernel/tests/include/lapi/setns.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef LAPI_SETNS_H__
+#define LAPI_SETNS_H__
+
+#include "config.h"
+#include "lapi/syscalls.h"
+#include <sched.h>
+
+#ifndef HAVE_SETNS
+int setns(int fd, int nstype)
+{
+ return tst_syscall(__NR_setns, fd, nstype);
+}
+#endif
+
+#endif /* LAPI_SETNS_H__ */
diff --git a/src/kernel/tests/include/lapi/shm.h b/src/kernel/tests/include/lapi/shm.h
new file mode 100644
index 0000000..61c4e37
--- /dev/null
+++ b/src/kernel/tests/include/lapi/shm.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef LAPI_SHM_H__
+#define LAPI_SHM_H__
+
+#ifndef SHM_STAT_ANY
+# define SHM_STAT_ANY 15
+#endif
+
+#endif /* LAPI_SHM_H__ */
diff --git a/src/kernel/tests/include/lapi/shmbuf.h b/src/kernel/tests/include/lapi/shmbuf.h
new file mode 100644
index 0000000..28ee336
--- /dev/null
+++ b/src/kernel/tests/include/lapi/shmbuf.h
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef IPC_SHMBUF_H
+#define IPC_SHMBUF_H
+
+#include "lapi/posix_types.h"
+#include <sys/sem.h>
+#include "tst_timer.h"
+#include "ipcbuf.h"
+
+#ifndef HAVE_SHMID64_DS
+
+#if defined(__mips__)
+#define HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for the MIPS architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * As MIPS was lacking proper padding after shm_?time, we use 48 bits
+ * of the padding at the end to store a few additional bits of the time.
+ * libc implementations need to take care to convert this into a proper
+ * data structure when moving to 64-bit time_t.
+ */
+
+#if defined(__arch64__)
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+#else
+#define HAVE_SHMID64_DS_TIME_HIGH
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_ctime; /* last change time */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned short shm_atime_high;
+ unsigned short shm_dtime_high;
+ unsigned short shm_ctime_high;
+ unsigned short __unused1;
+};
+#endif
+
+#endif /* __mips__ */
+
+#if defined(__hppa__)
+#define HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+#if __BITS_PER_LONG == 64
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+#else
+#define HAVE_SHMID64_DS_TIME_HIGH
+ unsigned long shm_atime_high;
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_ctime_high;
+ unsigned long shm_ctime; /* last change time */
+ unsigned int __pad4;
+#endif
+ __kernel_size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+#endif /* __hppa__ */
+
+#if defined(__powerpc__) || defined(__powerpc64__)
+#define HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for PPC architecture.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+#ifdef __powerpc64__
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+#else
+#define HAVE_SHMID64_DS_TIME_HIGH
+ unsigned long shm_atime_high;
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_ctime_high;
+ unsigned long shm_ctime; /* last change time */
+ unsigned long __unused4;
+#endif
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused5;
+ unsigned long __unused6;
+};
+
+#endif /* defined(__powerpc__) || defined(__powerpc64__) */
+
+#if defined(__sparc__)
+#define HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for sparc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+#if defined(__arch64__)
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+#else
+#define HAVE_SHMID64_DS_TIME_HIGH
+ unsigned long shm_atime_high;
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_ctime_high;
+ unsigned long shm_ctime; /* last change time */
+#endif
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* __sparc__ */
+
+#if defined(__x86_64__) && defined(__ILP32__)
+#define HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for x86 architecture with x32 ABI.
+ *
+ * On x86-32 and x86-64 we can just use the generic definition, but
+ * x32 uses the same binary layout as x86_64, which is differnet
+ * from other 32-bit architectures.
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_long_t shm_atime; /* last attach time */
+ __kernel_long_t shm_dtime; /* last detach time */
+ __kernel_long_t shm_ctime; /* last change time */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ __kernel_ulong_t shm_nattch; /* no. of current attaches */
+ __kernel_ulong_t __unused4;
+ __kernel_ulong_t __unused5;
+};
+#endif /* defined(__x86_64__) && defined(__ILP32__) */
+
+#if defined(__xtensa__)
+#define HAVE_SHMID64_DS
+#define HAVE_SHMID64_DS_TIME_HIGH
+/*
+ * The shmid64_ds structure for Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space, but the padding is on the wrong
+ * side for big-endian xtensa, for historic reasons.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_atime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_ctime; /* last change time */
+ unsigned long shm_ctime_high;
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* __xtensa__ */
+
+#ifndef HAVE_SHMID64_DS
+/*
+ * The shmid64_ds structure for most architectures (though it came
+ * from x86_32 originally). Note extra padding because this structure
+ * is passed back and forth between kernel and user space.
+ *
+ * shmid64_ds was originally meant to be architecture specific, but
+ * everyone just ended up making identical copies without specific
+ * optimizations, so we may just as well all use the same one.
+ *
+ * 64 bit architectures use a 64-bit long time field here, while
+ * 32 bit architectures have a pair of unsigned long values.
+ * On big-endian systems, the lower half is in the wrong place.
+ *
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+#if __BITS_PER_LONG == 64
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+#else
+#define HAVE_SHMID64_DS_TIME_HIGH
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_atime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_ctime; /* last change time */
+ unsigned long shm_ctime_high;
+#endif
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#endif /* shmid64_ds */
+
+#endif /* HAVE_SHMID64_DS */
+
+#endif /* IPC_SHMBUF_H */
diff --git a/src/kernel/tests/include/lapi/signal.h b/src/kernel/tests/include/lapi/signal.h
new file mode 100644
index 0000000..d22965a
--- /dev/null
+++ b/src/kernel/tests/include/lapi/signal.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Daniel Díaz <daniel.diaz@linaro.org>
+ */
+
+#ifndef LAPI_SIGNAL_H
+#define LAPI_SIGNAL_H
+
+#include <signal.h>
+
+/*
+ * Some libc implementations might differ in the definitions they include. This
+ * covers those differences for all tests to successfully build.
+ */
+
+#ifndef __SIGRTMIN
+# define __SIGRTMIN 32
+#endif
+#ifndef __SIGRTMAX
+# define __SIGRTMAX (_NSIG - 1)
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/socket.h b/src/kernel/tests/include/lapi/socket.h
new file mode 100644
index 0000000..d6389e5
--- /dev/null
+++ b/src/kernel/tests/include/lapi/socket.h
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+* Copyright (c) 2016 Fujitsu Ltd.
+* Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+*/
+
+#ifndef __LAPI_SOCKET_H__
+#define __LAPI_SOCKET_H__
+
+#include "config.h"
+#include <sys/socket.h>
+
+#ifndef MSG_ZEROCOPY
+# define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */
+#endif
+
+#ifndef MSG_FASTOPEN
+# define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */
+#endif
+
+#ifndef SO_REUSEPORT
+# define SO_REUSEPORT 15
+#endif
+
+#ifndef SO_BUSY_POLL
+# define SO_BUSY_POLL 46
+#endif
+
+#ifndef SO_ATTACH_BPF
+# define SO_ATTACH_BPF 50
+#endif
+
+#ifndef SO_ZEROCOPY
+# define SO_ZEROCOPY 60
+#endif
+
+#ifndef SOCK_DCCP
+# define SOCK_DCCP 6
+#endif
+
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 02000000
+#endif
+
+#ifndef AF_ALG
+# define AF_ALG 38
+#endif
+
+#ifndef SOL_SCTP
+# define SOL_SCTP 132
+#endif
+
+#ifndef SOL_UDPLITE
+# define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */
+#endif
+
+#ifndef SOL_DCCP
+# define SOL_DCCP 269
+#endif
+
+#ifndef SOL_ALG
+# define SOL_ALG 279
+#endif
+
+#ifndef HAVE_STRUCT_MMSGHDR
+struct mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+#endif
+
+#endif /* __LAPI_SOCKET_H__ */
diff --git a/src/kernel/tests/include/lapi/splice.h b/src/kernel/tests/include/lapi/splice.h
new file mode 100644
index 0000000..0cd6f55
--- /dev/null
+++ b/src/kernel/tests/include/lapi/splice.h
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ */
+
+#ifndef SPLICE_H
+#define SPLICE_H
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_SPLICE)
+ssize_t splice(int fd_in, loff_t *off_in, int fd_out,
+ loff_t *off_out, size_t len, unsigned int flags)
+{
+ return tst_syscall(__NR_splice, fd_in, off_in,
+ fd_out, off_out, len, flags);
+}
+#endif
+
+#endif /* SPLICE_H */
diff --git a/src/kernel/tests/include/lapi/stat.h b/src/kernel/tests/include/lapi/stat.h
new file mode 100644
index 0000000..979e42d
--- /dev/null
+++ b/src/kernel/tests/include/lapi/stat.h
@@ -0,0 +1,257 @@
+//SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Referred from linux kernel -github/torvalds/linux/include/uapi/linux/fcntl.h
+ * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
+ * Email: code@zilogic.com
+ */
+#ifndef LAPI_STAT_H
+#define LAPI_STAT_H
+
+#include <stdint.h>
+#include <unistd.h>
+#include "lapi/syscalls.h"
+/*
+ * Timestamp structure for the timestamps in struct statx.
+ *
+ * tv_sec holds the number of seconds before (negative) or after (positive)
+ * 00:00:00 1st January 1970 UTC.
+ *
+ * tv_nsec holds a number of nanoseconds (0..999,999,999) after the tv_sec time.
+ *
+ * __reserved is held in case we need a yet finer resolution.
+ */
+#if defined(HAVE_STRUCT_STATX_TIMESTAMP)
+#include <sys/stat.h>
+#else
+struct statx_timestamp {
+ int64_t tv_sec;
+ uint32_t tv_nsec;
+ int32_t __reserved;
+};
+#endif
+/*
+ * Structures for the extended file attribute retrieval system call
+ * (statx()).
+ *
+ * The caller passes a mask of what they're specifically interested in as a
+ * parameter to statx(). What statx() actually got will be indicated in
+ * st_mask upon return.
+ *
+ * For each bit in the mask argument:
+ *
+ * - if the datum is not supported:
+ *
+ * - the bit will be cleared, and
+ *
+ * - the datum will be set to an appropriate fabricated value if one is
+ * available (eg. CIFS can take a default uid and gid), otherwise
+ *
+ * - the field will be cleared;
+ *
+ * - otherwise, if explicitly requested:
+ *
+ * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
+ * set or if the datum is considered out of date, and
+ *
+ * - the field will be filled in and the bit will be set;
+ *
+ * - otherwise, if not requested, but available in approximate form without any
+ * effort, it will be filled in anyway, and the bit will be set upon return
+ * (it might not be up to date, however, and no attempt will be made to
+ * synchronise the internal state first);
+ *
+ * - otherwise the field and the bit will be cleared before returning.
+ *
+ * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
+ * will have values installed for compatibility purposes so that stat() and
+ * co. can be emulated in userspace.
+ */
+#if defined(HAVE_STRUCT_STATX)
+#include <sys/stat.h>
+#else
+struct statx {
+ /* 0x00 */
+ uint32_t stx_mask;
+ uint32_t stx_blksize;
+ uint64_t stx_attributes;
+ /* 0x10 */
+ uint32_t stx_nlink;
+ uint32_t stx_uid;
+ uint32_t stx_gid;
+ uint16_t stx_mode;
+ uint16_t __spare0[1];
+ /* 0x20 */
+ uint64_t stx_ino;
+ uint64_t stx_size;
+ uint64_t stx_blocks;
+ uint64_t stx_attributes_mask;
+ /* 0x40 */
+ const struct statx_timestamp stx_atime;
+ const struct statx_timestamp stx_btime;
+ const struct statx_timestamp stx_ctime;
+ const struct statx_timestamp stx_mtime;
+ /* 0x80 */
+ uint32_t stx_rdev_major;
+ uint32_t stx_rdev_minor;
+ uint32_t stx_dev_major;
+ uint32_t stx_dev_minor;
+ /* 0x90 */
+ uint64_t __spare2[14];
+ /* 0x100 */
+};
+#endif
+
+#if !defined(HAVE_STATX)
+
+/*
+ * statx: wrapper function of statx
+ *
+ * Returns: It returns status of statx syscall
+ */
+static inline int statx(int dirfd, const char *pathname, unsigned int flags,
+ unsigned int mask, struct statx *statxbuf)
+{
+ return tst_syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
+}
+#endif
+
+/*
+ * 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().
+ */
+#ifndef STATX_TYPE
+# define STATX_TYPE 0x00000001U
+#endif
+
+#ifndef STATX_MODE
+# define STATX_MODE 0x00000002U
+#endif
+
+#ifndef STATX_NLINK
+# define STATX_NLINK 0x00000004U
+#endif
+
+#ifndef STATX_UID
+# define STATX_UID 0x00000008U
+#endif
+
+#ifndef STATX_GID
+# define STATX_GID 0x00000010U
+#endif
+
+#ifndef STATX_ATIME
+# define STATX_ATIME 0x00000020U
+#endif
+
+#ifndef STATX_MTIME
+# define STATX_MTIME 0x00000040U
+#endif
+
+#ifndef STATX_CTIME
+# define STATX_CTIME 0x00000080U
+#endif
+
+#ifndef STATX_INO
+# define STATX_INO 0x00000100U
+#endif
+
+#ifndef STATX_SIZE
+# define STATX_SIZE 0x00000200U
+#endif
+
+#ifndef STATX_BLOCKS
+# define STATX_BLOCKS 0x00000400U
+#endif
+
+#ifndef STATX_BASIC_STATS
+# define STATX_BASIC_STATS 0x000007ffU
+#endif
+
+#ifndef STATX_BTIME
+# define STATX_BTIME 0x00000800U
+#endif
+
+#ifndef STATX_ALL
+# define STATX_ALL 0x00000fffU
+#endif
+
+#ifndef STATX__RESERVED
+# define STATX__RESERVED 0x80000000U
+#endif
+
+/*
+ * 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.
+ */
+#ifndef STATX_ATTR_COMPRESSED
+# define STATX_ATTR_COMPRESSED 0x00000004
+#endif
+
+#ifndef STATX_ATTR_IMMUTABLE
+# define STATX_ATTR_IMMUTABLE 0x00000010
+#endif
+
+#ifndef STATX_ATTR_APPEND
+# define STATX_ATTR_APPEND 0x00000020
+#endif
+
+#ifndef STATX_ATTR_NODUMP
+# define STATX_ATTR_NODUMP 0x00000040
+#endif
+
+#ifndef STATX_ATTR_ENCRYPTED
+# define STATX_ATTR_ENCRYPTED 0x00000800
+#endif
+
+#ifndef STATX_ATTR_AUTOMOUNT
+# define STATX_ATTR_AUTOMOUNT 0x00001000
+#endif
+
+#ifndef AT_SYMLINK_NOFOLLOW
+# define AT_SYMLINK_NOFOLLOW 0x100
+#endif
+
+#ifndef AT_REMOVEDIR
+# define AT_REMOVEDIR 0x200
+#endif
+
+#ifndef AT_SYMLINK_FOLLOW
+# define AT_SYMLINK_FOLLOW 0x400
+#endif
+
+#ifndef AT_NO_AUTOMOUNT
+# define AT_NO_AUTOMOUNT 0x800
+#endif
+
+#ifndef AT_EMPTY_PATH
+# define AT_EMPTY_PATH 0x1000
+#endif
+
+#ifndef AT_STATX_SYNC_TYPE
+# define AT_STATX_SYNC_TYPE 0x6000
+#endif
+
+#ifndef AT_STATX_SYNC_AS_STAT
+# define AT_STATX_SYNC_AS_STAT 0x0000
+#endif
+
+#ifndef AT_STATX_FORCE_SYNC
+# define AT_STATX_FORCE_SYNC 0x2000
+#endif
+
+#ifndef AT_STATX_DONT_SYNC
+# define AT_STATX_DONT_SYNC 0x4000
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/sync_file_range.h b/src/kernel/tests/include/lapi/sync_file_range.h
new file mode 100644
index 0000000..86bfe5d
--- /dev/null
+++ b/src/kernel/tests/include/lapi/sync_file_range.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2008
+ */
+
+#ifndef SYNC_FILE_RANGE_H
+#define SYNC_FILE_RANGE_H
+
+#include <sys/types.h>
+#include "config.h"
+#include "lapi/syscalls.h"
+#include "lapi/abisize.h"
+
+#if !defined(HAVE_SYNC_FILE_RANGE)
+
+#ifdef TST_TEST_H__
+# define TST_SYSCALL tst_syscall
+#else
+# define TST_SYSCALL ltp_syscall
+#endif
+
+/*****************************************************************************
+ * Wraper function to call sync_file_range system call
+ ******************************************************************************/
+static inline long sync_file_range(int fd, off64_t offset, off64_t nbytes,
+ unsigned int flags)
+{
+#if (defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__))
+# ifdef TST_ABI32
+# if __BYTE_ORDER == __BIG_ENDIAN
+ return TST_SYSCALL(__NR_sync_file_range2, fd, flags,
+ (int)(offset >> 32), (int)offset, (int)(nbytes >> 32),
+ (int)nbytes);
+# elif __BYTE_ORDER == __LITTLE_ENDIAN
+ return TST_SYSCALL(__NR_sync_file_range2, fd, flags, (int)offset,
+ (int)(offset >> 32), nbytes, (int)(nbytes >> 32));
+# endif
+# else
+ return TST_SYSCALL(__NR_sync_file_range2, fd, flags, offset, nbytes);
+# endif
+#elif (defined(__s390__) || defined(__s390x__)) && defined(TST_ABI32)
+ return TST_SYSCALL(__NR_sync_file_range, fd, (int)(offset >> 32),
+ (int)offset, (int)(nbytes >> 32), (int)nbytes, flags);
+#elif defined(__mips__) && defined(TST_ABI32)
+# if __BYTE_ORDER == __BIG_ENDIAN
+ return TST_SYSCALL(__NR_sync_file_range, fd, 0, (int)(offset >> 32),
+ (int)offset, (int)(nbytes >> 32), (int)nbytes, flags);
+# elif __BYTE_ORDER == __LITTLE_ENDIAN
+ return TST_SYSCALL(__NR_sync_file_range, fd, 0, (int)offset,
+ (int)(offset >> 32), (int)nbytes, (int)(nbytes >> 32), flags);
+# endif
+#else
+ return TST_SYSCALL(__NR_sync_file_range, fd, offset, nbytes, flags);
+#endif
+}
+#endif
+
+#endif /* SYNC_FILE_RANGE_H */
diff --git a/src/kernel/tests/include/lapi/syncfs.h b/src/kernel/tests/include/lapi/syncfs.h
new file mode 100644
index 0000000..e5d29fa
--- /dev/null
+++ b/src/kernel/tests/include/lapi/syncfs.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ */
+
+#ifndef SYNCFS_H
+#define SYNCFS_H
+
+#include "config.h"
+#include <sys/types.h>
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_SYNCFS)
+int syncfs(int fd)
+{
+ return tst_syscall(__NR_syncfs, fd);
+}
+#endif
+
+#endif /* SYNCFS_H */
diff --git a/src/kernel/tests/include/lapi/syscalls.h b/src/kernel/tests/include/lapi/syscalls.h
new file mode 100644
index 0000000..251d0ed
--- /dev/null
+++ b/src/kernel/tests/include/lapi/syscalls.h
@@ -0,0 +1,19964 @@
+/************************************************
+ * GENERATED FILE: DO NOT EDIT/PATCH THIS FILE *
+ * change your arch specific .in file instead *
+ ************************************************/
+
+/*
+ * Here we stick all the ugly *fallback* logic for linux
+ * system call numbers (those __NR_ thingies).
+ *
+ * Licensed under the GPLv2 or later, see the COPYING file.
+ */
+
+#ifndef __LAPI_SYSCALLS_H__
+#define __LAPI_SYSCALLS_H__
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <asm/unistd.h>
+#include "cleanup.c"
+
+#define ltp_syscall(NR, ...) ({ \
+ int __ret; \
+ if (NR == __LTP__NR_INVALID_SYSCALL) { \
+ errno = ENOSYS; \
+ __ret = -1; \
+ } else { \
+ __ret = syscall(NR, ##__VA_ARGS__); \
+ } \
+ if (__ret == -1 && errno == ENOSYS) { \
+ tst_brkm(TCONF, CLEANUP, \
+ "syscall(%d) " #NR " not supported on your arch", \
+ NR); \
+ } \
+ __ret; \
+})
+
+#define tst_syscall(NR, ...) ({ \
+ int tst_ret; \
+ if (NR == __LTP__NR_INVALID_SYSCALL) { \
+ errno = ENOSYS; \
+ tst_ret = -1; \
+ } else { \
+ tst_ret = syscall(NR, ##__VA_ARGS__); \
+ } \
+ if (tst_ret == -1 && errno == ENOSYS) { \
+ tst_brk(TCONF, "syscall(%d) " #NR " not supported", NR); \
+ } \
+ tst_ret; \
+})
+
+#define __LTP__NR_INVALID_SYSCALL -1
+
+#ifdef __aarch64__
+# ifndef __NR_io_setup
+# define __NR_io_setup 0
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 1
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 2
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 3
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 4
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 5
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 6
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 7
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 8
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 9
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 10
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 11
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 12
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 13
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 14
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 15
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 16
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 17
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 18
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 19
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 20
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 21
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 22
+# endif
+# ifndef __NR_dup
+# define __NR_dup 23
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 24
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 25
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 26
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 27
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 28
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 29
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 30
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 31
+# endif
+# ifndef __NR_flock
+# define __NR_flock 32
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 33
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 34
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 35
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 36
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 37
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 38
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 39
+# endif
+# ifndef __NR_mount
+# define __NR_mount 40
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 41
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 42
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 43
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 44
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 45
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 46
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 47
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 48
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 49
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 50
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 51
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 52
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 53
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 54
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 55
+# endif
+# ifndef __NR_openat
+# define __NR_openat 56
+# endif
+# ifndef __NR_close
+# define __NR_close 57
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 58
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 59
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 60
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 61
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 62
+# endif
+# ifndef __NR_read
+# define __NR_read 63
+# endif
+# ifndef __NR_write
+# define __NR_write 64
+# endif
+# ifndef __NR_readv
+# define __NR_readv 65
+# endif
+# ifndef __NR_writev
+# define __NR_writev 66
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 67
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 68
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 69
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 70
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 71
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 72
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 73
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 74
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 75
+# endif
+# ifndef __NR_splice
+# define __NR_splice 76
+# endif
+# ifndef __NR_tee
+# define __NR_tee 77
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 78
+# endif
+# ifndef __NR_fstatat
+# define __NR_fstatat 79
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 80
+# endif
+# ifndef __NR_sync
+# define __NR_sync 81
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 82
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 83
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 84
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 84
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 85
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 86
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 87
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 88
+# endif
+# ifndef __NR_acct
+# define __NR_acct 89
+# endif
+# ifndef __NR_capget
+# define __NR_capget 90
+# endif
+# ifndef __NR_capset
+# define __NR_capset 91
+# endif
+# ifndef __NR_personality
+# define __NR_personality 92
+# endif
+# ifndef __NR_exit
+# define __NR_exit 93
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 94
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 95
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 96
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 97
+# endif
+# ifndef __NR_futex
+# define __NR_futex 98
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 99
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 100
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 101
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 102
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 103
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 104
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 105
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 106
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 107
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 108
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 109
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 110
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 111
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 112
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 113
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 114
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 115
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 116
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 117
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 118
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 119
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 120
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 121
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 122
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 123
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 124
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 125
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 126
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 127
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 128
+# endif
+# ifndef __NR_kill
+# define __NR_kill 129
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 130
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 131
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 132
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 133
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 134
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 135
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 136
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 137
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 138
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 139
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 140
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 141
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 142
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 143
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 144
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 145
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 146
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 147
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 148
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 149
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 150
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 151
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 152
+# endif
+# ifndef __NR_times
+# define __NR_times 153
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 154
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 155
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 156
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 157
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 158
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 159
+# endif
+# ifndef __NR_uname
+# define __NR_uname 160
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 161
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 162
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 163
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 164
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 165
+# endif
+# ifndef __NR_umask
+# define __NR_umask 166
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 167
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 168
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 169
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 170
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 171
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 172
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 173
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 174
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 175
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 176
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 177
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 178
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 179
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 180
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 181
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 182
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 183
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 184
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 185
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 186
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 187
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 188
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 189
+# endif
+# ifndef __NR_semget
+# define __NR_semget 190
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 191
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 192
+# endif
+# ifndef __NR_semop
+# define __NR_semop 193
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 194
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 195
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 196
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 197
+# endif
+# ifndef __NR_socket
+# define __NR_socket 198
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 199
+# endif
+# ifndef __NR_bind
+# define __NR_bind 200
+# endif
+# ifndef __NR_listen
+# define __NR_listen 201
+# endif
+# ifndef __NR_accept
+# define __NR_accept 202
+# endif
+# ifndef __NR_connect
+# define __NR_connect 203
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 204
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 205
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 206
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 207
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 208
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 209
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 210
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 211
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 212
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 213
+# endif
+# ifndef __NR_brk
+# define __NR_brk 214
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 215
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 216
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 217
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 218
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 219
+# endif
+# ifndef __NR_clone
+# define __NR_clone 220
+# endif
+# ifndef __NR_execve
+# define __NR_execve 221
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 222
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 223
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 224
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 225
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 226
+# endif
+# ifndef __NR_msync
+# define __NR_msync 227
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 228
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 229
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 230
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 231
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 232
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 233
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 234
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 235
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 236
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 237
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 238
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 239
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 240
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 241
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 242
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 243
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 260
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 261
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 262
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 263
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 264
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 265
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 266
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 267
+# endif
+# ifndef __NR_setns
+# define __NR_setns 268
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 269
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 270
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 271
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 272
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 273
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 274
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 275
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 276
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 277
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 278
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 279
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 280
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 281
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 282
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 283
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 284
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 285
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 286
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 287
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 288
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 289
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 290
+# endif
+# ifndef __NR_statx
+# define __NR_statx 291
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 292
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 293
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 294
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 1078
+# endif
+#endif
+
+
+#ifdef __arc__
+# ifndef __NR_io_setup
+# define __NR_io_setup 0
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 1
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 2
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 3
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 4
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 5
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 6
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 7
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 8
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 9
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 10
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 11
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 12
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 13
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 14
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 15
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 16
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 17
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 18
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 19
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 20
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 21
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 22
+# endif
+# ifndef __NR_dup
+# define __NR_dup 23
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 24
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 25
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 26
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 27
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 28
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 29
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 30
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 31
+# endif
+# ifndef __NR_flock
+# define __NR_flock 32
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 33
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 34
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 35
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 36
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 37
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 38
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 39
+# endif
+# ifndef __NR_mount
+# define __NR_mount 40
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 41
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 42
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 43
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 44
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 45
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 46
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 47
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 48
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 49
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 50
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 51
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 52
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 53
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 54
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 55
+# endif
+# ifndef __NR_openat
+# define __NR_openat 56
+# endif
+# ifndef __NR_close
+# define __NR_close 57
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 58
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 59
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 60
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 61
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 62
+# endif
+# ifndef __NR_read
+# define __NR_read 63
+# endif
+# ifndef __NR_write
+# define __NR_write 64
+# endif
+# ifndef __NR_readv
+# define __NR_readv 65
+# endif
+# ifndef __NR_writev
+# define __NR_writev 66
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 67
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 68
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 69
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 70
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 71
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 72
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 73
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 74
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 75
+# endif
+# ifndef __NR_splice
+# define __NR_splice 76
+# endif
+# ifndef __NR_tee
+# define __NR_tee 77
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 78
+# endif
+# ifndef __NR_fstatat
+# define __NR_fstatat 79
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 80
+# endif
+# ifndef __NR_sync
+# define __NR_sync 81
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 82
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 83
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 84
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 84
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 85
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 86
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 87
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 88
+# endif
+# ifndef __NR_acct
+# define __NR_acct 89
+# endif
+# ifndef __NR_capget
+# define __NR_capget 90
+# endif
+# ifndef __NR_capset
+# define __NR_capset 91
+# endif
+# ifndef __NR_personality
+# define __NR_personality 92
+# endif
+# ifndef __NR_exit
+# define __NR_exit 93
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 94
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 95
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 96
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 97
+# endif
+# ifndef __NR_futex
+# define __NR_futex 98
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 99
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 100
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 101
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 102
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 103
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 104
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 105
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 106
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 107
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 108
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 109
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 110
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 111
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 112
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 113
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 114
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 115
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 116
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 117
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 118
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 119
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 120
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 121
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 122
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 123
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 124
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 125
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 126
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 127
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 128
+# endif
+# ifndef __NR_kill
+# define __NR_kill 129
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 130
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 131
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 132
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 133
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 134
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 135
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 136
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 137
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 138
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 139
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 140
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 141
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 142
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 143
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 144
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 145
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 146
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 147
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 148
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 149
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 150
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 151
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 152
+# endif
+# ifndef __NR_times
+# define __NR_times 153
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 154
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 155
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 156
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 157
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 158
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 159
+# endif
+# ifndef __NR_uname
+# define __NR_uname 160
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 161
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 162
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 163
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 164
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 165
+# endif
+# ifndef __NR_umask
+# define __NR_umask 166
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 167
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 168
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 169
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 170
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 171
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 172
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 173
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 174
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 175
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 176
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 177
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 178
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 179
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 180
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 181
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 182
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 183
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 184
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 185
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 186
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 187
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 188
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 189
+# endif
+# ifndef __NR_semget
+# define __NR_semget 190
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 191
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 192
+# endif
+# ifndef __NR_semop
+# define __NR_semop 193
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 194
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 195
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 196
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 197
+# endif
+# ifndef __NR_socket
+# define __NR_socket 198
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 199
+# endif
+# ifndef __NR_bind
+# define __NR_bind 200
+# endif
+# ifndef __NR_listen
+# define __NR_listen 201
+# endif
+# ifndef __NR_accept
+# define __NR_accept 202
+# endif
+# ifndef __NR_connect
+# define __NR_connect 203
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 204
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 205
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 206
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 207
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 208
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 209
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 210
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 211
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 212
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 213
+# endif
+# ifndef __NR_brk
+# define __NR_brk 214
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 215
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 216
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 217
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 218
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 219
+# endif
+# ifndef __NR_clone
+# define __NR_clone 220
+# endif
+# ifndef __NR_execve
+# define __NR_execve 221
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 222
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 223
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 224
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 225
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 226
+# endif
+# ifndef __NR_msync
+# define __NR_msync 227
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 228
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 229
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 230
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 231
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 232
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 233
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 234
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 235
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 236
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 237
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 238
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 239
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 240
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 241
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 242
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 243
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush 244
+# endif
+# ifndef __NR_arc_settls
+# define __NR_arc_settls 245
+# endif
+# ifndef __NR_arc_gettls
+# define __NR_arc_gettls 246
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 247
+# endif
+# ifndef __NR_arc_usr_cmpxchg
+# define __NR_arc_usr_cmpxchg 248
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 260
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 261
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 262
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 263
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 264
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 265
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 266
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 267
+# endif
+# ifndef __NR_setns
+# define __NR_setns 268
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 269
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 270
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 271
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 272
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 278
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 279
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 280
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 281
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 282
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 283
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 284
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 285
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 286
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 287
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 288
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 289
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 290
+# endif
+# ifndef __NR_statx
+# define __NR_statx 291
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 292
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 293
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 294
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __arm__
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0)
+# endif
+# ifndef __NR_exit
+# define __NR_exit (__NR_SYSCALL_BASE+ 1)
+# endif
+# ifndef __NR_fork
+# define __NR_fork (__NR_SYSCALL_BASE+ 2)
+# endif
+# ifndef __NR_read
+# define __NR_read (__NR_SYSCALL_BASE+ 3)
+# endif
+# ifndef __NR_write
+# define __NR_write (__NR_SYSCALL_BASE+ 4)
+# endif
+# ifndef __NR_open
+# define __NR_open (__NR_SYSCALL_BASE+ 5)
+# endif
+# ifndef __NR_close
+# define __NR_close (__NR_SYSCALL_BASE+ 6)
+# endif
+# ifndef __NR_creat
+# define __NR_creat (__NR_SYSCALL_BASE+ 8)
+# endif
+# ifndef __NR_link
+# define __NR_link (__NR_SYSCALL_BASE+ 9)
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink (__NR_SYSCALL_BASE+ 10)
+# endif
+# ifndef __NR_execve
+# define __NR_execve (__NR_SYSCALL_BASE+ 11)
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir (__NR_SYSCALL_BASE+ 12)
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod (__NR_SYSCALL_BASE+ 14)
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod (__NR_SYSCALL_BASE+ 15)
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown (__NR_SYSCALL_BASE+ 16)
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek (__NR_SYSCALL_BASE+ 19)
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid (__NR_SYSCALL_BASE+ 20)
+# endif
+# ifndef __NR_mount
+# define __NR_mount (__NR_SYSCALL_BASE+ 21)
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid (__NR_SYSCALL_BASE+ 23)
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid (__NR_SYSCALL_BASE+ 24)
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace (__NR_SYSCALL_BASE+ 26)
+# endif
+# ifndef __NR_pause
+# define __NR_pause (__NR_SYSCALL_BASE+ 29)
+# endif
+# ifndef __NR_access
+# define __NR_access (__NR_SYSCALL_BASE+ 33)
+# endif
+# ifndef __NR_nice
+# define __NR_nice (__NR_SYSCALL_BASE+ 34)
+# endif
+# ifndef __NR_sync
+# define __NR_sync (__NR_SYSCALL_BASE+ 36)
+# endif
+# ifndef __NR_kill
+# define __NR_kill (__NR_SYSCALL_BASE+ 37)
+# endif
+# ifndef __NR_rename
+# define __NR_rename (__NR_SYSCALL_BASE+ 38)
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir (__NR_SYSCALL_BASE+ 39)
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir (__NR_SYSCALL_BASE+ 40)
+# endif
+# ifndef __NR_dup
+# define __NR_dup (__NR_SYSCALL_BASE+ 41)
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe (__NR_SYSCALL_BASE+ 42)
+# endif
+# ifndef __NR_times
+# define __NR_times (__NR_SYSCALL_BASE+ 43)
+# endif
+# ifndef __NR_brk
+# define __NR_brk (__NR_SYSCALL_BASE+ 45)
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid (__NR_SYSCALL_BASE+ 46)
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid (__NR_SYSCALL_BASE+ 47)
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid (__NR_SYSCALL_BASE+ 49)
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid (__NR_SYSCALL_BASE+ 50)
+# endif
+# ifndef __NR_acct
+# define __NR_acct (__NR_SYSCALL_BASE+ 51)
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 (__NR_SYSCALL_BASE+ 52)
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl (__NR_SYSCALL_BASE+ 54)
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl (__NR_SYSCALL_BASE+ 55)
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid (__NR_SYSCALL_BASE+ 57)
+# endif
+# ifndef __NR_umask
+# define __NR_umask (__NR_SYSCALL_BASE+ 60)
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot (__NR_SYSCALL_BASE+ 61)
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat (__NR_SYSCALL_BASE+ 62)
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 (__NR_SYSCALL_BASE+ 63)
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid (__NR_SYSCALL_BASE+ 64)
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp (__NR_SYSCALL_BASE+ 65)
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid (__NR_SYSCALL_BASE+ 66)
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction (__NR_SYSCALL_BASE+ 67)
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid (__NR_SYSCALL_BASE+ 70)
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid (__NR_SYSCALL_BASE+ 71)
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend (__NR_SYSCALL_BASE+ 72)
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending (__NR_SYSCALL_BASE+ 73)
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname (__NR_SYSCALL_BASE+ 74)
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit (__NR_SYSCALL_BASE+ 75)
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage (__NR_SYSCALL_BASE+ 77)
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday (__NR_SYSCALL_BASE+ 78)
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday (__NR_SYSCALL_BASE+ 79)
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups (__NR_SYSCALL_BASE+ 80)
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups (__NR_SYSCALL_BASE+ 81)
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink (__NR_SYSCALL_BASE+ 83)
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink (__NR_SYSCALL_BASE+ 85)
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib (__NR_SYSCALL_BASE+ 86)
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon (__NR_SYSCALL_BASE+ 87)
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot (__NR_SYSCALL_BASE+ 88)
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap (__NR_SYSCALL_BASE+ 91)
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate (__NR_SYSCALL_BASE+ 92)
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate (__NR_SYSCALL_BASE+ 93)
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod (__NR_SYSCALL_BASE+ 94)
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown (__NR_SYSCALL_BASE+ 95)
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority (__NR_SYSCALL_BASE+ 96)
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority (__NR_SYSCALL_BASE+ 97)
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs (__NR_SYSCALL_BASE+ 99)
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs (__NR_SYSCALL_BASE+100)
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog (__NR_SYSCALL_BASE+103)
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer (__NR_SYSCALL_BASE+104)
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer (__NR_SYSCALL_BASE+105)
+# endif
+# ifndef __NR_stat
+# define __NR_stat (__NR_SYSCALL_BASE+106)
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat (__NR_SYSCALL_BASE+107)
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat (__NR_SYSCALL_BASE+108)
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup (__NR_SYSCALL_BASE+111)
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 (__NR_SYSCALL_BASE+114)
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff (__NR_SYSCALL_BASE+115)
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo (__NR_SYSCALL_BASE+116)
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync (__NR_SYSCALL_BASE+118)
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn (__NR_SYSCALL_BASE+119)
+# endif
+# ifndef __NR_clone
+# define __NR_clone (__NR_SYSCALL_BASE+120)
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname (__NR_SYSCALL_BASE+121)
+# endif
+# ifndef __NR_uname
+# define __NR_uname (__NR_SYSCALL_BASE+122)
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex (__NR_SYSCALL_BASE+124)
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect (__NR_SYSCALL_BASE+125)
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask (__NR_SYSCALL_BASE+126)
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module (__NR_SYSCALL_BASE+128)
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module (__NR_SYSCALL_BASE+129)
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl (__NR_SYSCALL_BASE+131)
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid (__NR_SYSCALL_BASE+132)
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir (__NR_SYSCALL_BASE+133)
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush (__NR_SYSCALL_BASE+134)
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs (__NR_SYSCALL_BASE+135)
+# endif
+# ifndef __NR_personality
+# define __NR_personality (__NR_SYSCALL_BASE+136)
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid (__NR_SYSCALL_BASE+138)
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid (__NR_SYSCALL_BASE+139)
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek (__NR_SYSCALL_BASE+140)
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents (__NR_SYSCALL_BASE+141)
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect (__NR_SYSCALL_BASE+142)
+# endif
+# ifndef __NR_flock
+# define __NR_flock (__NR_SYSCALL_BASE+143)
+# endif
+# ifndef __NR_msync
+# define __NR_msync (__NR_SYSCALL_BASE+144)
+# endif
+# ifndef __NR_readv
+# define __NR_readv (__NR_SYSCALL_BASE+145)
+# endif
+# ifndef __NR_writev
+# define __NR_writev (__NR_SYSCALL_BASE+146)
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid (__NR_SYSCALL_BASE+147)
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync (__NR_SYSCALL_BASE+148)
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl (__NR_SYSCALL_BASE+149)
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock (__NR_SYSCALL_BASE+150)
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock (__NR_SYSCALL_BASE+151)
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall (__NR_SYSCALL_BASE+152)
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall (__NR_SYSCALL_BASE+153)
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam (__NR_SYSCALL_BASE+154)
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam (__NR_SYSCALL_BASE+155)
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156)
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157)
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield (__NR_SYSCALL_BASE+158)
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159)
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160)
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161)
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep (__NR_SYSCALL_BASE+162)
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap (__NR_SYSCALL_BASE+163)
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid (__NR_SYSCALL_BASE+164)
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid (__NR_SYSCALL_BASE+165)
+# endif
+# ifndef __NR_poll
+# define __NR_poll (__NR_SYSCALL_BASE+168)
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl (__NR_SYSCALL_BASE+169)
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid (__NR_SYSCALL_BASE+170)
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid (__NR_SYSCALL_BASE+171)
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl (__NR_SYSCALL_BASE+172)
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173)
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction (__NR_SYSCALL_BASE+174)
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175)
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending (__NR_SYSCALL_BASE+176)
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177)
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178)
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179)
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 (__NR_SYSCALL_BASE+180)
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 (__NR_SYSCALL_BASE+181)
+# endif
+# ifndef __NR_chown
+# define __NR_chown (__NR_SYSCALL_BASE+182)
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd (__NR_SYSCALL_BASE+183)
+# endif
+# ifndef __NR_capget
+# define __NR_capget (__NR_SYSCALL_BASE+184)
+# endif
+# ifndef __NR_capset
+# define __NR_capset (__NR_SYSCALL_BASE+185)
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack (__NR_SYSCALL_BASE+186)
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile (__NR_SYSCALL_BASE+187)
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork (__NR_SYSCALL_BASE+190)
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit (__NR_SYSCALL_BASE+191)
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 (__NR_SYSCALL_BASE+192)
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 (__NR_SYSCALL_BASE+193)
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 (__NR_SYSCALL_BASE+194)
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 (__NR_SYSCALL_BASE+195)
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 (__NR_SYSCALL_BASE+196)
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 (__NR_SYSCALL_BASE+197)
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 (__NR_SYSCALL_BASE+198)
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 (__NR_SYSCALL_BASE+199)
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 (__NR_SYSCALL_BASE+200)
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 (__NR_SYSCALL_BASE+201)
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 (__NR_SYSCALL_BASE+202)
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 (__NR_SYSCALL_BASE+203)
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 (__NR_SYSCALL_BASE+204)
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 (__NR_SYSCALL_BASE+205)
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 (__NR_SYSCALL_BASE+206)
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 (__NR_SYSCALL_BASE+207)
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 (__NR_SYSCALL_BASE+208)
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 (__NR_SYSCALL_BASE+209)
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 (__NR_SYSCALL_BASE+210)
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 (__NR_SYSCALL_BASE+211)
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 (__NR_SYSCALL_BASE+212)
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 (__NR_SYSCALL_BASE+213)
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 (__NR_SYSCALL_BASE+214)
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 (__NR_SYSCALL_BASE+215)
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 (__NR_SYSCALL_BASE+216)
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 (__NR_SYSCALL_BASE+217)
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root (__NR_SYSCALL_BASE+218)
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore (__NR_SYSCALL_BASE+219)
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise (__NR_SYSCALL_BASE+220)
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 (__NR_SYSCALL_BASE+221)
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid (__NR_SYSCALL_BASE+224)
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead (__NR_SYSCALL_BASE+225)
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr (__NR_SYSCALL_BASE+226)
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr (__NR_SYSCALL_BASE+228)
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr (__NR_SYSCALL_BASE+229)
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr (__NR_SYSCALL_BASE+231)
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr (__NR_SYSCALL_BASE+232)
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr (__NR_SYSCALL_BASE+233)
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr (__NR_SYSCALL_BASE+234)
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr (__NR_SYSCALL_BASE+235)
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr (__NR_SYSCALL_BASE+236)
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr (__NR_SYSCALL_BASE+237)
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill (__NR_SYSCALL_BASE+238)
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 (__NR_SYSCALL_BASE+239)
+# endif
+# ifndef __NR_futex
+# define __NR_futex (__NR_SYSCALL_BASE+240)
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity (__NR_SYSCALL_BASE+241)
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity (__NR_SYSCALL_BASE+242)
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup (__NR_SYSCALL_BASE+243)
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy (__NR_SYSCALL_BASE+244)
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents (__NR_SYSCALL_BASE+245)
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit (__NR_SYSCALL_BASE+246)
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel (__NR_SYSCALL_BASE+247)
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group (__NR_SYSCALL_BASE+248)
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249)
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create (__NR_SYSCALL_BASE+250)
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl (__NR_SYSCALL_BASE+251)
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait (__NR_SYSCALL_BASE+252)
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages (__NR_SYSCALL_BASE+253)
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address (__NR_SYSCALL_BASE+256)
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create (__NR_SYSCALL_BASE+257)
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime (__NR_SYSCALL_BASE+258)
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime (__NR_SYSCALL_BASE+259)
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun (__NR_SYSCALL_BASE+260)
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete (__NR_SYSCALL_BASE+261)
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime (__NR_SYSCALL_BASE+262)
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime (__NR_SYSCALL_BASE+263)
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres (__NR_SYSCALL_BASE+264)
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep (__NR_SYSCALL_BASE+265)
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 (__NR_SYSCALL_BASE+266)
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 (__NR_SYSCALL_BASE+267)
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill (__NR_SYSCALL_BASE+268)
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes (__NR_SYSCALL_BASE+269)
+# endif
+# ifndef __NR_arm_fadvise64_64
+# define __NR_arm_fadvise64_64 (__NR_SYSCALL_BASE+270)
+# endif
+# ifndef __NR_pciconfig_iobase
+# define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271)
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read (__NR_SYSCALL_BASE+272)
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write (__NR_SYSCALL_BASE+273)
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open (__NR_SYSCALL_BASE+274)
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink (__NR_SYSCALL_BASE+275)
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend (__NR_SYSCALL_BASE+276)
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive (__NR_SYSCALL_BASE+277)
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify (__NR_SYSCALL_BASE+278)
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279)
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid (__NR_SYSCALL_BASE+280)
+# endif
+# ifndef __NR_socket
+# define __NR_socket (__NR_SYSCALL_BASE+281)
+# endif
+# ifndef __NR_bind
+# define __NR_bind (__NR_SYSCALL_BASE+282)
+# endif
+# ifndef __NR_connect
+# define __NR_connect (__NR_SYSCALL_BASE+283)
+# endif
+# ifndef __NR_listen
+# define __NR_listen (__NR_SYSCALL_BASE+284)
+# endif
+# ifndef __NR_accept
+# define __NR_accept (__NR_SYSCALL_BASE+285)
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname (__NR_SYSCALL_BASE+286)
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername (__NR_SYSCALL_BASE+287)
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair (__NR_SYSCALL_BASE+288)
+# endif
+# ifndef __NR_send
+# define __NR_send (__NR_SYSCALL_BASE+289)
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto (__NR_SYSCALL_BASE+290)
+# endif
+# ifndef __NR_recv
+# define __NR_recv (__NR_SYSCALL_BASE+291)
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom (__NR_SYSCALL_BASE+292)
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown (__NR_SYSCALL_BASE+293)
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt (__NR_SYSCALL_BASE+294)
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt (__NR_SYSCALL_BASE+295)
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg (__NR_SYSCALL_BASE+296)
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg (__NR_SYSCALL_BASE+297)
+# endif
+# ifndef __NR_semop
+# define __NR_semop (__NR_SYSCALL_BASE+298)
+# endif
+# ifndef __NR_semget
+# define __NR_semget (__NR_SYSCALL_BASE+299)
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl (__NR_SYSCALL_BASE+300)
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd (__NR_SYSCALL_BASE+301)
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv (__NR_SYSCALL_BASE+302)
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget (__NR_SYSCALL_BASE+303)
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl (__NR_SYSCALL_BASE+304)
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat (__NR_SYSCALL_BASE+305)
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt (__NR_SYSCALL_BASE+306)
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget (__NR_SYSCALL_BASE+307)
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl (__NR_SYSCALL_BASE+308)
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key (__NR_SYSCALL_BASE+309)
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key (__NR_SYSCALL_BASE+310)
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl (__NR_SYSCALL_BASE+311)
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop (__NR_SYSCALL_BASE+312)
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver (__NR_SYSCALL_BASE+313)
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set (__NR_SYSCALL_BASE+314)
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get (__NR_SYSCALL_BASE+315)
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind (__NR_SYSCALL_BASE+319)
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy (__NR_SYSCALL_BASE+320)
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
+# endif
+# ifndef __NR_openat
+# define __NR_openat (__NR_SYSCALL_BASE+322)
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat (__NR_SYSCALL_BASE+323)
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat (__NR_SYSCALL_BASE+324)
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat (__NR_SYSCALL_BASE+325)
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat (__NR_SYSCALL_BASE+326)
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 (__NR_SYSCALL_BASE+327)
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat (__NR_SYSCALL_BASE+328)
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat (__NR_SYSCALL_BASE+329)
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat (__NR_SYSCALL_BASE+330)
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat (__NR_SYSCALL_BASE+331)
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat (__NR_SYSCALL_BASE+332)
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat (__NR_SYSCALL_BASE+333)
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat (__NR_SYSCALL_BASE+334)
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 (__NR_SYSCALL_BASE+335)
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll (__NR_SYSCALL_BASE+336)
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare (__NR_SYSCALL_BASE+337)
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
+# endif
+# ifndef __NR_splice
+# define __NR_splice (__NR_SYSCALL_BASE+340)
+# endif
+# ifndef __NR_arm_sync_file_range
+# define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341)
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 __NR_arm_sync_file_range
+# endif
+# ifndef __NR_tee
+# define __NR_tee (__NR_SYSCALL_BASE+342)
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice (__NR_SYSCALL_BASE+343)
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages (__NR_SYSCALL_BASE+344)
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu (__NR_SYSCALL_BASE+345)
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load (__NR_SYSCALL_BASE+347)
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat (__NR_SYSCALL_BASE+348)
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd (__NR_SYSCALL_BASE+349)
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd (__NR_SYSCALL_BASE+351)
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate (__NR_SYSCALL_BASE+352)
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 (__NR_SYSCALL_BASE+355)
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 (__NR_SYSCALL_BASE+356)
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 (__NR_SYSCALL_BASE+357)
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 (__NR_SYSCALL_BASE+358)
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 (__NR_SYSCALL_BASE+359)
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 (__NR_SYSCALL_BASE+360)
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv (__NR_SYSCALL_BASE+361)
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev (__NR_SYSCALL_BASE+362)
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363)
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open (__NR_SYSCALL_BASE+364)
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg (__NR_SYSCALL_BASE+365)
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 (__NR_SYSCALL_BASE+366)
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init (__NR_SYSCALL_BASE+367)
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark (__NR_SYSCALL_BASE+368)
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 (__NR_SYSCALL_BASE+369)
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370)
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371)
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime (__NR_SYSCALL_BASE+372)
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs (__NR_SYSCALL_BASE+373)
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg (__NR_SYSCALL_BASE+374)
+# endif
+# ifndef __NR_setns
+# define __NR_setns (__NR_SYSCALL_BASE+375)
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp (__NR_SYSCALL_BASE+378)
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module (__NR_SYSCALL_BASE+379)
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 (__NR_SYSCALL_BASE+382)
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp (__NR_SYSCALL_BASE+383)
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom (__NR_SYSCALL_BASE+384)
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create (__NR_SYSCALL_BASE+385)
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf (__NR_SYSCALL_BASE+386)
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat (__NR_SYSCALL_BASE+387)
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd (__NR_SYSCALL_BASE+388)
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier (__NR_SYSCALL_BASE+389)
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 (__NR_SYSCALL_BASE+390)
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range (__NR_SYSCALL_BASE+391)
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 (__NR_SYSCALL_BASE+392)
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 (__NR_SYSCALL_BASE+393)
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect (__NR_SYSCALL_BASE+394)
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc (__NR_SYSCALL_BASE+395)
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free (__NR_SYSCALL_BASE+396)
+# endif
+# ifndef __NR_statx
+# define __NR_statx (__NR_SYSCALL_BASE+397)
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq (__NR_SYSCALL_BASE+398)
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents (__NR_SYSCALL_BASE+399)
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages (__NR_SYSCALL_BASE+400)
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load (__NR_SYSCALL_BASE+401)
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 (__NR_SYSCALL_BASE+403)
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 (__NR_SYSCALL_BASE+404)
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 (__NR_SYSCALL_BASE+405)
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 (__NR_SYSCALL_BASE+406)
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 (__NR_SYSCALL_BASE+407)
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 (__NR_SYSCALL_BASE+408)
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 (__NR_SYSCALL_BASE+409)
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 (__NR_SYSCALL_BASE+410)
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 (__NR_SYSCALL_BASE+411)
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 (__NR_SYSCALL_BASE+412)
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 (__NR_SYSCALL_BASE+413)
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 (__NR_SYSCALL_BASE+414)
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 (__NR_SYSCALL_BASE+416)
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 (__NR_SYSCALL_BASE+417)
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 (__NR_SYSCALL_BASE+418)
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 (__NR_SYSCALL_BASE+419)
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 (__NR_SYSCALL_BASE+420)
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 (__NR_SYSCALL_BASE+421)
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 (__NR_SYSCALL_BASE+422)
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 (__NR_SYSCALL_BASE+423)
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal (__NR_SYSCALL_BASE+424)
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup (__NR_SYSCALL_BASE+425)
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter (__NR_SYSCALL_BASE+426)
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register (__NR_SYSCALL_BASE+427)
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree (__NR_SYSCALL_BASE+428)
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount (__NR_SYSCALL_BASE+429)
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen (__NR_SYSCALL_BASE+430)
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig (__NR_SYSCALL_BASE+431)
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount (__NR_SYSCALL_BASE+432)
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick (__NR_SYSCALL_BASE+433)
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open (__NR_SYSCALL_BASE+434)
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 (__NR_SYSCALL_BASE+435)
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 (__NR_SYSCALL_BASE+437)
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd (__NR_SYSCALL_BASE+438)
+# endif
+#endif
+
+
+#ifdef __hppa__
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_openat
+# define __NR_openat 275
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat (__NR_openat + 1)
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat (__NR_openat + 2)
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat (__NR_openat + 3)
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat (__NR_openat + 4)
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat (__NR_openat + 5)
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 (__NR_openat + 5)
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat (__NR_openat + 6)
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat (__NR_openat + 7)
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat (__NR_openat + 8)
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat (__NR_openat + 9)
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat (__NR_openat + 10)
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat (__NR_openat + 11)
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat (__NR_openat + 12)
+# endif
+# ifndef __NR_splice
+# define __NR_splice 291
+# endif
+# ifndef __NR_tee
+# define __NR_tee 293
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 294
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 327
+# endif
+# ifndef __NR_setns
+# define __NR_setns 328
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 330
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 331
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 340
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 343
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 342
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 345
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 346
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 347
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 348
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 350
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+#endif
+
+
+#ifdef __i386__
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_break
+# define __NR_break 17
+# endif
+# ifndef __NR_oldstat
+# define __NR_oldstat 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_oldfstat
+# define __NR_oldfstat 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_stty
+# define __NR_stty 31
+# endif
+# ifndef __NR_gtty
+# define __NR_gtty 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_ftime
+# define __NR_ftime 35
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_prof
+# define __NR_prof 44
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_lock
+# define __NR_lock 53
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_mpx
+# define __NR_mpx 56
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_ulimit
+# define __NR_ulimit 58
+# endif
+# ifndef __NR_oldolduname
+# define __NR_oldolduname 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 68
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 69
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_select
+# define __NR_select 82
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 84
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_profil
+# define __NR_profil 98
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 101
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_olduname
+# define __NR_olduname 109
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_vm86old
+# define __NR_vm86old 113
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt 123
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 164
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 165
+# endif
+# ifndef __NR_vm86
+# define __NR_vm86 166
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 167
+# endif
+# ifndef __NR_poll
+# define __NR_poll 168
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 169
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 170
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 171
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 172
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 173
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 174
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 175
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 176
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 177
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 178
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 179
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 180
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 181
+# endif
+# ifndef __NR_chown
+# define __NR_chown 182
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 183
+# endif
+# ifndef __NR_capget
+# define __NR_capget 184
+# endif
+# ifndef __NR_capset
+# define __NR_capset 185
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 186
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 187
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 188
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 189
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 190
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit 191
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 192
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 193
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 194
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 195
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 196
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 197
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 198
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 199
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 200
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 201
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 202
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 203
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 204
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 205
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 206
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 207
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 208
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 209
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 210
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 211
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 212
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 213
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 214
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 215
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 216
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 217
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 218
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 219
+# endif
+# ifndef __NR_madvise1
+# define __NR_madvise1 219
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 220
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 221
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 224
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 225
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 226
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 227
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 228
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 229
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 230
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 231
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 232
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 233
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 234
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 235
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 236
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 237
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 238
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 239
+# endif
+# ifndef __NR_futex
+# define __NR_futex 240
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 241
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 242
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 243
+# endif
+# ifndef __NR_get_thread_area
+# define __NR_get_thread_area 244
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 245
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 246
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 247
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 248
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 249
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 250
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 252
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 253
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 254
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 255
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 256
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 257
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 258
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 259
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 260
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 261
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 262
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 263
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 264
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 265
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 266
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 267
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 268
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 269
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 270
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 271
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 272
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 273
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 274
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 275
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 276
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 277
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 278
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 279
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 280
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 281
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 282
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 283
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 284
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 286
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 287
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 288
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 289
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 290
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 291
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 292
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 293
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 294
+# endif
+# ifndef __NR_openat
+# define __NR_openat 295
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 296
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 297
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 298
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 299
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 300
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 301
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 302
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 303
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 304
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 305
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 306
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 307
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 308
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 309
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 310
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 311
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 312
+# endif
+# ifndef __NR_splice
+# define __NR_splice 313
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 314
+# endif
+# ifndef __NR_tee
+# define __NR_tee 315
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 316
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 317
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 318
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 319
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 320
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 321
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 322
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 323
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 324
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 325
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 326
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 327
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 328
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 329
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 330
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 331
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 332
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 333
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 334
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 335
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 336
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 337
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 338
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 339
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 340
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 341
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 342
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 343
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 344
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 345
+# endif
+# ifndef __NR_setns
+# define __NR_setns 346
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 347
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 348
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 349
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 350
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 351
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 352
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 353
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 354
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 355
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 356
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 357
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 358
+# endif
+# ifndef __NR_socket
+# define __NR_socket 359
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 360
+# endif
+# ifndef __NR_bind
+# define __NR_bind 361
+# endif
+# ifndef __NR_connect
+# define __NR_connect 362
+# endif
+# ifndef __NR_listen
+# define __NR_listen 363
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 364
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 365
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 366
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 367
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 368
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 369
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 370
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 371
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 372
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 373
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 374
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 375
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 376
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 377
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 378
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 379
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 380
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 381
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 382
+# endif
+# ifndef __NR_statx
+# define __NR_statx 383
+# endif
+# ifndef __NR_arch_prctl
+# define __NR_arch_prctl 384
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 385
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 386
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __ia64__
+# ifndef __NR_ni_syscall
+# define __NR_ni_syscall 1024
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1025
+# endif
+# ifndef __NR_read
+# define __NR_read 1026
+# endif
+# ifndef __NR_write
+# define __NR_write 1027
+# endif
+# ifndef __NR_open
+# define __NR_open 1028
+# endif
+# ifndef __NR_close
+# define __NR_close 1029
+# endif
+# ifndef __NR_creat
+# define __NR_creat 1030
+# endif
+# ifndef __NR_link
+# define __NR_link 1031
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 1032
+# endif
+# ifndef __NR_execve
+# define __NR_execve 1033
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 1034
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 1035
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 1036
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 1037
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 1038
+# endif
+# ifndef __NR_chown
+# define __NR_chown 1039
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 1040
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 1041
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 1042
+# endif
+# ifndef __NR_mount
+# define __NR_mount 1043
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 1044
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 1045
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 1046
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 1047
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 1048
+# endif
+# ifndef __NR_access
+# define __NR_access 1049
+# endif
+# ifndef __NR_sync
+# define __NR_sync 1050
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 1051
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 1052
+# endif
+# ifndef __NR_kill
+# define __NR_kill 1053
+# endif
+# ifndef __NR_rename
+# define __NR_rename 1054
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 1055
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 1056
+# endif
+# ifndef __NR_dup
+# define __NR_dup 1057
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 1058
+# endif
+# ifndef __NR_times
+# define __NR_times 1059
+# endif
+# ifndef __NR_brk
+# define __NR_brk 1060
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 1061
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 1062
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 1063
+# endif
+# ifndef __NR_acct
+# define __NR_acct 1064
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 1065
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 1066
+# endif
+# ifndef __NR_umask
+# define __NR_umask 1067
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 1068
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 1069
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 1070
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 1071
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 1072
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 1073
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 1074
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 1075
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 1076
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 1077
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 1078
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 1079
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 1080
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 1081
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 1082
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 1083
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 1084
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 1085
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 1086
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 1087
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 1088
+# endif
+# ifndef __NR_select
+# define __NR_select 1089
+# endif
+# ifndef __NR_poll
+# define __NR_poll 1090
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 1091
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 1092
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 1093
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 1094
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 1095
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 1096
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 1097
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 1098
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 1099
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 1100
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 1101
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 1102
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 1103
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 1104
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 1105
+# endif
+# ifndef __NR_semget
+# define __NR_semget 1106
+# endif
+# ifndef __NR_semop
+# define __NR_semop 1107
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 1108
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 1109
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 1110
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 1111
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 1112
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 1113
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 1114
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 1115
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 1116
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 1117
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 1118
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 1119
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 1123
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 1124
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 1125
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 1126
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 1127
+# endif
+# ifndef __NR_clone
+# define __NR_clone 1128
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 1129
+# endif
+# ifndef __NR_uname
+# define __NR_uname 1130
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 1131
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 1133
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 1134
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 1137
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 1138
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 1139
+# endif
+# ifndef __NR_personality
+# define __NR_personality 1140
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 1141
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 1142
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 1143
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 1144
+# endif
+# ifndef __NR_flock
+# define __NR_flock 1145
+# endif
+# ifndef __NR_readv
+# define __NR_readv 1146
+# endif
+# ifndef __NR_writev
+# define __NR_writev 1147
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 1148
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 1149
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 1150
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 1151
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 1152
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 1153
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 1154
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 1155
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 1156
+# endif
+# ifndef __NR_msync
+# define __NR_msync 1157
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 1158
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 1159
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 1160
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 1161
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 1162
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 1163
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 1164
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 1165
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 1166
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 1167
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 1168
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 1169
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 1170
+# endif
+# ifndef __NR_old_getpagesize
+# define __NR_old_getpagesize 1171
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 1172
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read 1173
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write 1174
+# endif
+# ifndef __NR_perfmonctl
+# define __NR_perfmonctl 1175
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 1176
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 1177
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 1178
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 1179
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 1180
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 1181
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 1182
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 1183
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 1184
+# endif
+# ifndef __NR_capget
+# define __NR_capget 1185
+# endif
+# ifndef __NR_capset
+# define __NR_capset 1186
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 1187
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 1188
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 1189
+# endif
+# ifndef __NR_socket
+# define __NR_socket 1190
+# endif
+# ifndef __NR_bind
+# define __NR_bind 1191
+# endif
+# ifndef __NR_connect
+# define __NR_connect 1192
+# endif
+# ifndef __NR_listen
+# define __NR_listen 1193
+# endif
+# ifndef __NR_accept
+# define __NR_accept 1194
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 1195
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 1196
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 1197
+# endif
+# ifndef __NR_send
+# define __NR_send 1198
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 1199
+# endif
+# ifndef __NR_recv
+# define __NR_recv 1200
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 1201
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 1202
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 1203
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 1204
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 1205
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 1206
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 1207
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 1208
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 1209
+# endif
+# ifndef __NR_stat
+# define __NR_stat 1210
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 1211
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 1212
+# endif
+# ifndef __NR_clone2
+# define __NR_clone2 1213
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 1214
+# endif
+# ifndef __NR_getunwind
+# define __NR_getunwind 1215
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 1216
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 1217
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 1218
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 1219
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 1220
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 1221
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 1222
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 1223
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 1224
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 1225
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 1226
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 1227
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 1228
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 1229
+# endif
+# ifndef __NR_futex
+# define __NR_futex 1230
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 1231
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 1232
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 1233
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 1234
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 1235
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 1236
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 1237
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 1238
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 1239
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 1240
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 1241
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 1242
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 1243
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 1244
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 1245
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 1246
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 1247
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 1248
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 1249
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 1250
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 1251
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 1252
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 1253
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 1254
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 1255
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 1256
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 1257
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 1258
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 1259
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 1260
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 1261
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 1262
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 1263
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 1264
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 1265
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 1266
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 1267
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 1268
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 1269
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 1270
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 1271
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 1272
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 1273
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 1274
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 1275
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 1276
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 1277
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 1278
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 1279
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 1280
+# endif
+# ifndef __NR_openat
+# define __NR_openat 1281
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 1282
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 1283
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 1284
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 1285
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 1286
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 1287
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 1288
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 1289
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 1290
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 1291
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 1292
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 1293
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 1294
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 1295
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 1296
+# endif
+# ifndef __NR_splice
+# define __NR_splice 1297
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 1298
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 1299
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 1300
+# endif
+# ifndef __NR_tee
+# define __NR_tee 1301
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 1302
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 1303
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 1304
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 1305
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 1306
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 1307
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 1308
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 1309
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 1310
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 1311
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 1312
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 1313
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 1314
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 1315
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 1316
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 1317
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 1318
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 1319
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 1320
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 1321
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 1322
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 1323
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 1324
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 1325
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 1326
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 1327
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 1328
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 1329
+# endif
+# ifndef __NR_setns
+# define __NR_setns 1330
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 1331
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 1332
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 1333
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 1334
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 1335
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 1336
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 1337
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 1338
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 1339
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 1340
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 1341
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 1342
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 1343
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 1344
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 1345
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 1346
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 1347
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 1348
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 1349
+# endif
+# ifndef __NR_statx
+# define __NR_statx 1350
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 1351
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 1352
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 1353
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 1354
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 1355
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 1356
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 1357
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 1448
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 1449
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 1450
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 1451
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 1452
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 1453
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 1454
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 1455
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 1456
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 1457
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 1458
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 1461
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 1462
+# endif
+#endif
+
+
+#if defined(__mips__) && defined(_ABIN32)
+# ifndef __NR_read
+# define __NR_read 0
+# endif
+# ifndef __NR_write
+# define __NR_write 1
+# endif
+# ifndef __NR_open
+# define __NR_open 2
+# endif
+# ifndef __NR_close
+# define __NR_close 3
+# endif
+# ifndef __NR_stat
+# define __NR_stat 4
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 5
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 6
+# endif
+# ifndef __NR_poll
+# define __NR_poll 7
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 8
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 9
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 10
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 11
+# endif
+# ifndef __NR_brk
+# define __NR_brk 12
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 13
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 14
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 15
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 16
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 17
+# endif
+# ifndef __NR_readv
+# define __NR_readv 18
+# endif
+# ifndef __NR_writev
+# define __NR_writev 19
+# endif
+# ifndef __NR_access
+# define __NR_access 20
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 21
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 22
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 23
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 24
+# endif
+# ifndef __NR_msync
+# define __NR_msync 25
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 26
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 27
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 28
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 29
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 30
+# endif
+# ifndef __NR_dup
+# define __NR_dup 31
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 32
+# endif
+# ifndef __NR_pause
+# define __NR_pause 33
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 34
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 35
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 36
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 37
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 38
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 39
+# endif
+# ifndef __NR_socket
+# define __NR_socket 40
+# endif
+# ifndef __NR_connect
+# define __NR_connect 41
+# endif
+# ifndef __NR_accept
+# define __NR_accept 42
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 43
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 44
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 45
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 46
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 47
+# endif
+# ifndef __NR_bind
+# define __NR_bind 48
+# endif
+# ifndef __NR_listen
+# define __NR_listen 49
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 50
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 51
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 52
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 53
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 54
+# endif
+# ifndef __NR_clone
+# define __NR_clone 55
+# endif
+# ifndef __NR_fork
+# define __NR_fork 56
+# endif
+# ifndef __NR_execve
+# define __NR_execve 57
+# endif
+# ifndef __NR_exit
+# define __NR_exit 58
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 59
+# endif
+# ifndef __NR_kill
+# define __NR_kill 60
+# endif
+# ifndef __NR_uname
+# define __NR_uname 61
+# endif
+# ifndef __NR_semget
+# define __NR_semget 62
+# endif
+# ifndef __NR_semop
+# define __NR_semop 63
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 64
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 65
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 66
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 67
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 68
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 69
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 70
+# endif
+# ifndef __NR_flock
+# define __NR_flock 71
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 72
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 73
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 74
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 75
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 76
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 77
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 78
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 79
+# endif
+# ifndef __NR_rename
+# define __NR_rename 80
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 81
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 82
+# endif
+# ifndef __NR_creat
+# define __NR_creat 83
+# endif
+# ifndef __NR_link
+# define __NR_link 84
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 85
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 86
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 87
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 88
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 89
+# endif
+# ifndef __NR_chown
+# define __NR_chown 90
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 91
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 92
+# endif
+# ifndef __NR_umask
+# define __NR_umask 93
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 94
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 95
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 96
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 97
+# endif
+# ifndef __NR_times
+# define __NR_times 98
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 99
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 100
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 101
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 102
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 103
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 104
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 105
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 106
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 107
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 108
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 109
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 110
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 111
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 112
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 113
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 114
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 115
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 116
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 117
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 118
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 119
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 120
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 121
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 122
+# endif
+# ifndef __NR_capget
+# define __NR_capget 123
+# endif
+# ifndef __NR_capset
+# define __NR_capset 124
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 125
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 126
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 127
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 128
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 129
+# endif
+# ifndef __NR_utime
+# define __NR_utime 130
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 131
+# endif
+# ifndef __NR_personality
+# define __NR_personality 132
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 133
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 134
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 135
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 136
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 137
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 138
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 139
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 140
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 141
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 142
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 143
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 144
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 145
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 146
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 147
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 148
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 149
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 150
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 151
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 152
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 153
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 154
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 155
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 156
+# endif
+# ifndef __NR_sync
+# define __NR_sync 157
+# endif
+# ifndef __NR_acct
+# define __NR_acct 158
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 159
+# endif
+# ifndef __NR_mount
+# define __NR_mount 160
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 161
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 162
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 163
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 164
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 165
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 166
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 167
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 168
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 169
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 170
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 171
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 172
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 173
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 174
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 175
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 176
+# endif
+# ifndef __NR_reserved177
+# define __NR_reserved177 177
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 178
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 179
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 180
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 181
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 182
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 183
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 184
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 185
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 186
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 187
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 188
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 189
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 190
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 191
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 192
+# endif
+# ifndef __NR_reserved193
+# define __NR_reserved193 193
+# endif
+# ifndef __NR_futex
+# define __NR_futex 194
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 195
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 196
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush 197
+# endif
+# ifndef __NR_cachectl
+# define __NR_cachectl 198
+# endif
+# ifndef __NR_sysmips
+# define __NR_sysmips 199
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 200
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 201
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 202
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 203
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 204
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 205
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 206
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 207
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 208
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 209
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 210
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 211
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 212
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 213
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 214
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 215
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 216
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 217
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 218
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 219
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 220
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 221
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 222
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 223
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 224
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 225
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 226
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 227
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 228
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 229
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 230
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 231
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 232
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 233
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 234
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 235
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 236
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 237
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 238
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 239
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 240
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 241
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 243
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 244
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 245
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 246
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 247
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 248
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 249
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 250
+# endif
+# ifndef __NR_openat
+# define __NR_openat 251
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 252
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 253
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 254
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 255
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 256
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 257
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 258
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 259
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 260
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 261
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 262
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 263
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 264
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 265
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 266
+# endif
+# ifndef __NR_splice
+# define __NR_splice 267
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 268
+# endif
+# ifndef __NR_tee
+# define __NR_tee 269
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 270
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 271
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 272
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 273
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 274
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 275
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 276
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 277
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 278
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 279
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 280
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 281
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 282
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 283
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 284
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 285
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 286
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 287
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 288
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 289
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 290
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 291
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 292
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 293
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 294
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 295
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 296
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 297
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 298
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 299
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 300
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 301
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 302
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 303
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 304
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 305
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 306
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 307
+# endif
+# ifndef __NR_setns
+# define __NR_setns 308
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 309
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 310
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 311
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 312
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 313
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 314
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 315
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 316
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 317
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 318
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 319
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 320
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 321
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 322
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 323
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 324
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 325
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 326
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 327
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 328
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 329
+# endif
+# ifndef __NR_statx
+# define __NR_statx 330
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 331
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 332
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#if defined(__mips__) && defined(_ABI64)
+# ifndef __NR_read
+# define __NR_read 0
+# endif
+# ifndef __NR_write
+# define __NR_write 1
+# endif
+# ifndef __NR_open
+# define __NR_open 2
+# endif
+# ifndef __NR_close
+# define __NR_close 3
+# endif
+# ifndef __NR_stat
+# define __NR_stat 4
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 5
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 6
+# endif
+# ifndef __NR_poll
+# define __NR_poll 7
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 8
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 9
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 10
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 11
+# endif
+# ifndef __NR_brk
+# define __NR_brk 12
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 13
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 14
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 15
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 16
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 17
+# endif
+# ifndef __NR_readv
+# define __NR_readv 18
+# endif
+# ifndef __NR_writev
+# define __NR_writev 19
+# endif
+# ifndef __NR_access
+# define __NR_access 20
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 21
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 22
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 23
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 24
+# endif
+# ifndef __NR_msync
+# define __NR_msync 25
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 26
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 27
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 28
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 29
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 30
+# endif
+# ifndef __NR_dup
+# define __NR_dup 31
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 32
+# endif
+# ifndef __NR_pause
+# define __NR_pause 33
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 34
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 35
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 36
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 37
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 38
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 39
+# endif
+# ifndef __NR_socket
+# define __NR_socket 40
+# endif
+# ifndef __NR_connect
+# define __NR_connect 41
+# endif
+# ifndef __NR_accept
+# define __NR_accept 42
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 43
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 44
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 45
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 46
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 47
+# endif
+# ifndef __NR_bind
+# define __NR_bind 48
+# endif
+# ifndef __NR_listen
+# define __NR_listen 49
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 50
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 51
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 52
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 53
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 54
+# endif
+# ifndef __NR_clone
+# define __NR_clone 55
+# endif
+# ifndef __NR_fork
+# define __NR_fork 56
+# endif
+# ifndef __NR_execve
+# define __NR_execve 57
+# endif
+# ifndef __NR_exit
+# define __NR_exit 58
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 59
+# endif
+# ifndef __NR_kill
+# define __NR_kill 60
+# endif
+# ifndef __NR_uname
+# define __NR_uname 61
+# endif
+# ifndef __NR_semget
+# define __NR_semget 62
+# endif
+# ifndef __NR_semop
+# define __NR_semop 63
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 64
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 65
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 66
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 67
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 68
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 69
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 70
+# endif
+# ifndef __NR_flock
+# define __NR_flock 71
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 72
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 73
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 74
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 75
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 76
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 77
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 78
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 79
+# endif
+# ifndef __NR_rename
+# define __NR_rename 80
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 81
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 82
+# endif
+# ifndef __NR_creat
+# define __NR_creat 83
+# endif
+# ifndef __NR_link
+# define __NR_link 84
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 85
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 86
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 87
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 88
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 89
+# endif
+# ifndef __NR_chown
+# define __NR_chown 90
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 91
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 92
+# endif
+# ifndef __NR_umask
+# define __NR_umask 93
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 94
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 95
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 96
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 97
+# endif
+# ifndef __NR_times
+# define __NR_times 98
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 99
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 100
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 101
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 102
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 103
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 104
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 105
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 106
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 107
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 108
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 109
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 110
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 111
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 112
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 113
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 114
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 115
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 116
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 117
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 118
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 119
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 120
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 121
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 122
+# endif
+# ifndef __NR_capget
+# define __NR_capget 123
+# endif
+# ifndef __NR_capset
+# define __NR_capset 124
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 125
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 126
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 127
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 128
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 129
+# endif
+# ifndef __NR_utime
+# define __NR_utime 130
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 131
+# endif
+# ifndef __NR_personality
+# define __NR_personality 132
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 133
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 134
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 135
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 136
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 137
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 138
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 139
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 140
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 141
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 142
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 143
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 144
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 145
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 146
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 147
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 148
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 149
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 150
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 151
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 152
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 153
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 154
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 155
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 156
+# endif
+# ifndef __NR_sync
+# define __NR_sync 157
+# endif
+# ifndef __NR_acct
+# define __NR_acct 158
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 159
+# endif
+# ifndef __NR_mount
+# define __NR_mount 160
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 161
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 162
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 163
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 164
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 165
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 166
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 167
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 168
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 169
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 170
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 171
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 172
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 173
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 174
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 175
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 176
+# endif
+# ifndef __NR_reserved177
+# define __NR_reserved177 177
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 178
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 179
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 180
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 181
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 182
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 183
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 184
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 185
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 186
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 187
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 188
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 189
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 190
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 191
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 192
+# endif
+# ifndef __NR_reserved193
+# define __NR_reserved193 193
+# endif
+# ifndef __NR_futex
+# define __NR_futex 194
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 195
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 196
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush 197
+# endif
+# ifndef __NR_cachectl
+# define __NR_cachectl 198
+# endif
+# ifndef __NR_sysmips
+# define __NR_sysmips 199
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 200
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 201
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 202
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 203
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 204
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 205
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 206
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 207
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 208
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 209
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 210
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 211
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 212
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 213
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 214
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 215
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 216
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 217
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 218
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 219
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 220
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 221
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 222
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 223
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 224
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 225
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 226
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 227
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 228
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 229
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 230
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 231
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 232
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 233
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 234
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 235
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 236
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 237
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 239
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 240
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 241
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 242
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 243
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 244
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 245
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 246
+# endif
+# ifndef __NR_openat
+# define __NR_openat 247
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 248
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 249
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 250
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 251
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 252
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 253
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 254
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 255
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 256
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 257
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 258
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 259
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 260
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 261
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 262
+# endif
+# ifndef __NR_splice
+# define __NR_splice 263
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 264
+# endif
+# ifndef __NR_tee
+# define __NR_tee 265
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 266
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 267
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 268
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 269
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 270
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 271
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 272
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 273
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 274
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 275
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 276
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 277
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 278
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 279
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 280
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 281
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 282
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 283
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 284
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 285
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 286
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 287
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 288
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 289
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 290
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 291
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 292
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 293
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 294
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 295
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 296
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 297
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 298
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 299
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 300
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 301
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 302
+# endif
+# ifndef __NR_setns
+# define __NR_setns 303
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 304
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 305
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 306
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 307
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 308
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 309
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 310
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 311
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 312
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 313
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 314
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 315
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 316
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 317
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 318
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 319
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 320
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 321
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 322
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 323
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 324
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 325
+# endif
+# ifndef __NR_statx
+# define __NR_statx 326
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 327
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 328
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#if defined(__mips__) && defined(_ABIO32)
+# ifndef __NR_syscall
+# define __NR_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_break
+# define __NR_break 17
+# endif
+# ifndef __NR_unused18
+# define __NR_unused18 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_unused28
+# define __NR_unused28 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_stty
+# define __NR_stty 31
+# endif
+# ifndef __NR_gtty
+# define __NR_gtty 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_ftime
+# define __NR_ftime 35
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_prof
+# define __NR_prof 44
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_lock
+# define __NR_lock 53
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_mpx
+# define __NR_mpx 56
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_ulimit
+# define __NR_ulimit 58
+# endif
+# ifndef __NR_unused59
+# define __NR_unused59 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 68
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 69
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_reserved82
+# define __NR_reserved82 82
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_unused84
+# define __NR_unused84 84
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_profil
+# define __NR_profil 98
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 101
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_unused109
+# define __NR_unused109 109
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_vm86
+# define __NR_vm86 113
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt 123
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush 147
+# endif
+# ifndef __NR_cachectl
+# define __NR_cachectl 148
+# endif
+# ifndef __NR_sysmips
+# define __NR_sysmips 149
+# endif
+# ifndef __NR_unused150
+# define __NR_unused150 150
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 151
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 152
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 153
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 154
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 155
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 156
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 157
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 158
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 159
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 160
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 161
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 162
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 163
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 164
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 165
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 166
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 167
+# endif
+# ifndef __NR_accept
+# define __NR_accept 168
+# endif
+# ifndef __NR_bind
+# define __NR_bind 169
+# endif
+# ifndef __NR_connect
+# define __NR_connect 170
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 171
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 172
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 173
+# endif
+# ifndef __NR_listen
+# define __NR_listen 174
+# endif
+# ifndef __NR_recv
+# define __NR_recv 175
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 176
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 177
+# endif
+# ifndef __NR_send
+# define __NR_send 178
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 179
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 180
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 181
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 182
+# endif
+# ifndef __NR_socket
+# define __NR_socket 183
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 184
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 185
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 186
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 187
+# endif
+# ifndef __NR_poll
+# define __NR_poll 188
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 189
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 190
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 191
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 192
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 193
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 194
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 195
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 196
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 197
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 198
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 199
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 200
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 201
+# endif
+# ifndef __NR_chown
+# define __NR_chown 202
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 203
+# endif
+# ifndef __NR_capget
+# define __NR_capget 204
+# endif
+# ifndef __NR_capset
+# define __NR_capset 205
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 206
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 207
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 208
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 209
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 210
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 211
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 212
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 213
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 214
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 215
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 216
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 217
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 218
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 219
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 220
+# endif
+# ifndef __NR_reserved221
+# define __NR_reserved221 221
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 222
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 223
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 224
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 225
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 226
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 227
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 228
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 229
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 230
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 231
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 232
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 233
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 234
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 235
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 236
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 237
+# endif
+# ifndef __NR_futex
+# define __NR_futex 238
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 239
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 240
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 241
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 242
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 243
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 244
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 245
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 246
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 247
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 248
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 249
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 250
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 251
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 252
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 253
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 254
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 255
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 256
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 257
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 258
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 259
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 260
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 261
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 262
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 263
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 264
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 265
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 266
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 267
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 268
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 269
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 270
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 271
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 272
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 273
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 274
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 275
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 276
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 277
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 278
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 280
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 281
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 282
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 283
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 284
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 285
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 286
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 287
+# endif
+# ifndef __NR_openat
+# define __NR_openat 288
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 289
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 290
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 291
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 292
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 293
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 294
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 295
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 296
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 297
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 298
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 299
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 300
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 301
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 302
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 303
+# endif
+# ifndef __NR_splice
+# define __NR_splice 304
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 305
+# endif
+# ifndef __NR_tee
+# define __NR_tee 306
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 307
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 308
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 309
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 310
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 311
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 312
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 313
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 314
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 315
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 316
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 317
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 318
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 319
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 320
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 321
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 322
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 323
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 324
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 325
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 326
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 327
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 328
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 329
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 330
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 331
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 332
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 333
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 334
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 335
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 336
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 337
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 338
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 339
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 340
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 341
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 342
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 343
+# endif
+# ifndef __NR_setns
+# define __NR_setns 344
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 345
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 346
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 347
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 348
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 349
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 350
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 351
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 352
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 353
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 354
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 355
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 356
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 357
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 358
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 359
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 360
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 361
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 362
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 363
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 364
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 365
+# endif
+# ifndef __NR_statx
+# define __NR_statx 366
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 367
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 368
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __powerpc64__
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_break
+# define __NR_break 17
+# endif
+# ifndef __NR_oldstat
+# define __NR_oldstat 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_oldfstat
+# define __NR_oldfstat 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_stty
+# define __NR_stty 31
+# endif
+# ifndef __NR_gtty
+# define __NR_gtty 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_ftime
+# define __NR_ftime 35
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_prof
+# define __NR_prof 44
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_lock
+# define __NR_lock 53
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_mpx
+# define __NR_mpx 56
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_ulimit
+# define __NR_ulimit 58
+# endif
+# ifndef __NR_oldolduname
+# define __NR_oldolduname 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 68
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 69
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_select
+# define __NR_select 82
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 84
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_profil
+# define __NR_profil 98
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 101
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_olduname
+# define __NR_olduname 109
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_vm86
+# define __NR_vm86 113
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt 123
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 164
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 165
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 166
+# endif
+# ifndef __NR_poll
+# define __NR_poll 167
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 168
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 169
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 170
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 171
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 172
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 173
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 174
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 175
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 176
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 177
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 178
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 179
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 180
+# endif
+# ifndef __NR_chown
+# define __NR_chown 181
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 182
+# endif
+# ifndef __NR_capget
+# define __NR_capget 183
+# endif
+# ifndef __NR_capset
+# define __NR_capset 184
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 185
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 186
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 187
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 188
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 189
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit 190
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 191
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 192
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 193
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 194
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 195
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 196
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 197
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read 198
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write 199
+# endif
+# ifndef __NR_pciconfig_iobase
+# define __NR_pciconfig_iobase 200
+# endif
+# ifndef __NR_multiplexer
+# define __NR_multiplexer 201
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 202
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 203
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 204
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 205
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 206
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 207
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 208
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 209
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 210
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 211
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 212
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 213
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 214
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 215
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 216
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 217
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 218
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 219
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 220
+# endif
+# ifndef __NR_futex
+# define __NR_futex 221
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 222
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 223
+# endif
+# ifndef __NR_tuxcall
+# define __NR_tuxcall 225
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 226
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 227
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 228
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 229
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 230
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 231
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 232
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 233
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 234
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 235
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 236
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 237
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 238
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 239
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 240
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 241
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 242
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 243
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 244
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 245
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 246
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 247
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 248
+# endif
+# ifndef __NR_swapcontext
+# define __NR_swapcontext 249
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 250
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 251
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 252
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 253
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 254
+# endif
+# ifndef __NR_rtas
+# define __NR_rtas 255
+# endif
+# ifndef __NR_sys_debug_setcontext
+# define __NR_sys_debug_setcontext 256
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 258
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 259
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 260
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 261
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 262
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 263
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 264
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 265
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 266
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 267
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 268
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 269
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 270
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 271
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 272
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 273
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 274
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 275
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 276
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 277
+# endif
+# ifndef __NR_spu_run
+# define __NR_spu_run 278
+# endif
+# ifndef __NR_spu_create
+# define __NR_spu_create 279
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 280
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 281
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 282
+# endif
+# ifndef __NR_splice
+# define __NR_splice 283
+# endif
+# ifndef __NR_tee
+# define __NR_tee 284
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 285
+# endif
+# ifndef __NR_openat
+# define __NR_openat 286
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 287
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 288
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 289
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 290
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 291
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 291
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 292
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 293
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 294
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 295
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 296
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 297
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 298
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 299
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 300
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 301
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 302
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 303
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 304
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 305
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 306
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 307
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 308
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 309
+# endif
+# ifndef __NR_subpage_prot
+# define __NR_subpage_prot 310
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 311
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 312
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 313
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 314
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 315
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 316
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 317
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 318
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 319
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 320
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 321
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 322
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 323
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 324
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 325
+# endif
+# ifndef __NR_socket
+# define __NR_socket 326
+# endif
+# ifndef __NR_bind
+# define __NR_bind 327
+# endif
+# ifndef __NR_connect
+# define __NR_connect 328
+# endif
+# ifndef __NR_listen
+# define __NR_listen 329
+# endif
+# ifndef __NR_accept
+# define __NR_accept 330
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 331
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 332
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 333
+# endif
+# ifndef __NR_send
+# define __NR_send 334
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 335
+# endif
+# ifndef __NR_recv
+# define __NR_recv 336
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 337
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 338
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 339
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 340
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 341
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 342
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 343
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 344
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 345
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 346
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 347
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 348
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 349
+# endif
+# ifndef __NR_setns
+# define __NR_setns 350
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 351
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 352
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 353
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 354
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 355
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 356
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 357
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 358
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 359
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 360
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 361
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 362
+# endif
+# ifndef __NR_switch_endian
+# define __NR_switch_endian 363
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 364
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 365
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 378
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 379
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 380
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 381
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 382
+# endif
+# ifndef __NR_statx
+# define __NR_statx 383
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 384
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 385
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 386
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 387
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 388
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 392
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __powerpc__
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_break
+# define __NR_break 17
+# endif
+# ifndef __NR_oldstat
+# define __NR_oldstat 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_oldfstat
+# define __NR_oldfstat 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_stty
+# define __NR_stty 31
+# endif
+# ifndef __NR_gtty
+# define __NR_gtty 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_ftime
+# define __NR_ftime 35
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_prof
+# define __NR_prof 44
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_lock
+# define __NR_lock 53
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_mpx
+# define __NR_mpx 56
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_ulimit
+# define __NR_ulimit 58
+# endif
+# ifndef __NR_oldolduname
+# define __NR_oldolduname 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 68
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 69
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_select
+# define __NR_select 82
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 84
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_profil
+# define __NR_profil 98
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 101
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_olduname
+# define __NR_olduname 109
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_vm86
+# define __NR_vm86 113
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt 123
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 164
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 165
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 166
+# endif
+# ifndef __NR_poll
+# define __NR_poll 167
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 168
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 169
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 170
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 171
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 172
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 173
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 174
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 175
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 176
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 177
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 178
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 179
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 180
+# endif
+# ifndef __NR_chown
+# define __NR_chown 181
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 182
+# endif
+# ifndef __NR_capget
+# define __NR_capget 183
+# endif
+# ifndef __NR_capset
+# define __NR_capset 184
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 185
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 186
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 187
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 188
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 189
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit 190
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 191
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 192
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 193
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 194
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 195
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 196
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 197
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read 198
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write 199
+# endif
+# ifndef __NR_pciconfig_iobase
+# define __NR_pciconfig_iobase 200
+# endif
+# ifndef __NR_multiplexer
+# define __NR_multiplexer 201
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 202
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 203
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 204
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 205
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 206
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 207
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 208
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 209
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 210
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 211
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 212
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 213
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 214
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 215
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 216
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 217
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 218
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 219
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 220
+# endif
+# ifndef __NR_futex
+# define __NR_futex 221
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 222
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 223
+# endif
+# ifndef __NR_tuxcall
+# define __NR_tuxcall 225
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 226
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 227
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 228
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 229
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 230
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 231
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 232
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 233
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 234
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 235
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 236
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 237
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 238
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 239
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 240
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 241
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 242
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 243
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 244
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 245
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 246
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 247
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 248
+# endif
+# ifndef __NR_swapcontext
+# define __NR_swapcontext 249
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 250
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 251
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 252
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 253
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 254
+# endif
+# ifndef __NR_rtas
+# define __NR_rtas 255
+# endif
+# ifndef __NR_sys_debug_setcontext
+# define __NR_sys_debug_setcontext 256
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 258
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 259
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 260
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 261
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 262
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 263
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 264
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 265
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 266
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 267
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 268
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 269
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 270
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 271
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 272
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 273
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 274
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 275
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 276
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 277
+# endif
+# ifndef __NR_spu_run
+# define __NR_spu_run 278
+# endif
+# ifndef __NR_spu_create
+# define __NR_spu_create 279
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 280
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 281
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 282
+# endif
+# ifndef __NR_splice
+# define __NR_splice 283
+# endif
+# ifndef __NR_tee
+# define __NR_tee 284
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 285
+# endif
+# ifndef __NR_openat
+# define __NR_openat 286
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 287
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 288
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 289
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 290
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 291
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 291
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 292
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 293
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 294
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 295
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 296
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 297
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 298
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 299
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 300
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 301
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 302
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 303
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 304
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 305
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 306
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 307
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 308
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 309
+# endif
+# ifndef __NR_subpage_prot
+# define __NR_subpage_prot 310
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 311
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 312
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 313
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 314
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 315
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 316
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 317
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 318
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 319
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 320
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 321
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 322
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 323
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 324
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 325
+# endif
+# ifndef __NR_socket
+# define __NR_socket 326
+# endif
+# ifndef __NR_bind
+# define __NR_bind 327
+# endif
+# ifndef __NR_connect
+# define __NR_connect 328
+# endif
+# ifndef __NR_listen
+# define __NR_listen 329
+# endif
+# ifndef __NR_accept
+# define __NR_accept 330
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 331
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 332
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 333
+# endif
+# ifndef __NR_send
+# define __NR_send 334
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 335
+# endif
+# ifndef __NR_recv
+# define __NR_recv 336
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 337
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 338
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 339
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 340
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 341
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 342
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 343
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 344
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 345
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 346
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 347
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 348
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 349
+# endif
+# ifndef __NR_setns
+# define __NR_setns 350
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 351
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 352
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 353
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 354
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 355
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 356
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 357
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 358
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 359
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 360
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 361
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 362
+# endif
+# ifndef __NR_switch_endian
+# define __NR_switch_endian 363
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 364
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 365
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 378
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 379
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 380
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 381
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 382
+# endif
+# ifndef __NR_statx
+# define __NR_statx 383
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 384
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 385
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 386
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 387
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 388
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 392
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __s390x__
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR_select
+# define __NR_select 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 167
+# endif
+# ifndef __NR_poll
+# define __NR_poll 168
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 169
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 172
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 173
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 174
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 175
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 176
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 177
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 178
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 179
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 180
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 181
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 183
+# endif
+# ifndef __NR_capget
+# define __NR_capget 184
+# endif
+# ifndef __NR_capset
+# define __NR_capset 185
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 186
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 187
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 188
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 189
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 190
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 191
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 198
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 199
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 200
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 201
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 202
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 203
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 204
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 205
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 206
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 207
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 208
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 209
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 210
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 211
+# endif
+# ifndef __NR_chown
+# define __NR_chown 212
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 213
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 214
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 215
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 216
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 217
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 218
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 219
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 220
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 222
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 224
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 225
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 226
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 227
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 228
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 229
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 230
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 231
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 232
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 233
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 234
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 235
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 236
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 237
+# endif
+# ifndef __NR_futex
+# define __NR_futex 238
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 239
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 240
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 241
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 243
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 244
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 245
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 246
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 247
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 248
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 249
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 250
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 251
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 252
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 253
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 254
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 255
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 256
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 257
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 258
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 259
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 260
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 261
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 262
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 265
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 266
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 267
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 268
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 269
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 270
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 271
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 272
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 273
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 274
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 275
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 276
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 277
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 278
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 279
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 280
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 281
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 282
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 283
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 284
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 285
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 286
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 287
+# endif
+# ifndef __NR_openat
+# define __NR_openat 288
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 289
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 290
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 291
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 292
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 293
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 294
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 295
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 296
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 297
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 298
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 299
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 300
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 301
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 302
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 303
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 304
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 305
+# endif
+# ifndef __NR_splice
+# define __NR_splice 306
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 307
+# endif
+# ifndef __NR_tee
+# define __NR_tee 308
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 309
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 310
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 311
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 312
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 313
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 314
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 315
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 316
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 317
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 318
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 319
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 320
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 321
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 322
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 323
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 324
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 325
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 326
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 327
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 328
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 329
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 330
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 331
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 332
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 333
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 334
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 335
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 336
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 337
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 338
+# endif
+# ifndef __NR_setns
+# define __NR_setns 339
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 340
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 341
+# endif
+# ifndef __NR_s390_runtime_instr
+# define __NR_s390_runtime_instr 342
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 343
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 344
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 345
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 346
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 347
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 348
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 349
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 350
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 351
+# endif
+# ifndef __NR_s390_pci_mmio_write
+# define __NR_s390_pci_mmio_write 352
+# endif
+# ifndef __NR_s390_pci_mmio_read
+# define __NR_s390_pci_mmio_read 353
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 354
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 355
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 356
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 357
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 358
+# endif
+# ifndef __NR_socket
+# define __NR_socket 359
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 360
+# endif
+# ifndef __NR_bind
+# define __NR_bind 361
+# endif
+# ifndef __NR_connect
+# define __NR_connect 362
+# endif
+# ifndef __NR_listen
+# define __NR_listen 363
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 364
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 365
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 366
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 367
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 368
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 369
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 370
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 371
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 372
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 373
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 374
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 375
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 376
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 377
+# endif
+# ifndef __NR_s390_guarded_storage
+# define __NR_s390_guarded_storage 378
+# endif
+# ifndef __NR_statx
+# define __NR_statx 379
+# endif
+# ifndef __NR_s390_sthyi
+# define __NR_s390_sthyi 380
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 381
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 382
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 383
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 384
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 385
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 386
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 392
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#if defined(__s390__) && !defined(__s390x__)
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 101
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 110
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_idle
+# define __NR_idle 112
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 127
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 130
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 137
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 164
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 165
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 167
+# endif
+# ifndef __NR_poll
+# define __NR_poll 168
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 169
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 170
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 171
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 172
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 173
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 174
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 175
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 176
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 177
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 178
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 179
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 180
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 181
+# endif
+# ifndef __NR_chown
+# define __NR_chown 182
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 183
+# endif
+# ifndef __NR_capget
+# define __NR_capget 184
+# endif
+# ifndef __NR_capset
+# define __NR_capset 185
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 186
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 187
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 188
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 189
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 190
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit 191
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 192
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 193
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 194
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 195
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 196
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 197
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 198
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 199
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 200
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 201
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 202
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 203
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 204
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 205
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 206
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 207
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 208
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 209
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 210
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 211
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 212
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 213
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 214
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 215
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 216
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 217
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 218
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 219
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 220
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 221
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 222
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 223
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 224
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 225
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 226
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 227
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 228
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 229
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 230
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 231
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 232
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 233
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 234
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 235
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 236
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 237
+# endif
+# ifndef __NR_futex
+# define __NR_futex 238
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 239
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 240
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 241
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 243
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 244
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 245
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 246
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 247
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 248
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 249
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 250
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 251
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 252
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 253
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 254
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 255
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 256
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 257
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 258
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 259
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 260
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 261
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 262
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 264
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 265
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 266
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 267
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 268
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 269
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 270
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 271
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 272
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 273
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 274
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 275
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 276
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 277
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 278
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 279
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 280
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 281
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 282
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 283
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 284
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 285
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 286
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 287
+# endif
+# ifndef __NR_openat
+# define __NR_openat 288
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 289
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 290
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 291
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 292
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 293
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 294
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 295
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 296
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 297
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 298
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 299
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 300
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 301
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 302
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 303
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 304
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 305
+# endif
+# ifndef __NR_splice
+# define __NR_splice 306
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 307
+# endif
+# ifndef __NR_tee
+# define __NR_tee 308
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 309
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 310
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 311
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 312
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 313
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 314
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 315
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 316
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd 317
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 318
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 319
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 320
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 321
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 322
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 323
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 324
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 325
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 326
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 327
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 328
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 329
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 330
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 331
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 332
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 333
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 334
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 335
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 336
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 337
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 338
+# endif
+# ifndef __NR_setns
+# define __NR_setns 339
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 340
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 341
+# endif
+# ifndef __NR_s390_runtime_instr
+# define __NR_s390_runtime_instr 342
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 343
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 344
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 345
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 346
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 347
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 348
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 349
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 350
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 351
+# endif
+# ifndef __NR_s390_pci_mmio_write
+# define __NR_s390_pci_mmio_write 352
+# endif
+# ifndef __NR_s390_pci_mmio_read
+# define __NR_s390_pci_mmio_read 353
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 354
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 355
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 356
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 357
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 358
+# endif
+# ifndef __NR_socket
+# define __NR_socket 359
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 360
+# endif
+# ifndef __NR_bind
+# define __NR_bind 361
+# endif
+# ifndef __NR_connect
+# define __NR_connect 362
+# endif
+# ifndef __NR_listen
+# define __NR_listen 363
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 364
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 365
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 366
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 367
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 368
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 369
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 370
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 371
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 372
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 373
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 374
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 375
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 376
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 377
+# endif
+# ifndef __NR_s390_guarded_storage
+# define __NR_s390_guarded_storage 378
+# endif
+# ifndef __NR_statx
+# define __NR_statx 379
+# endif
+# ifndef __NR_s390_sthyi
+# define __NR_s390_sthyi 380
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 381
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 382
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 383
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 384
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 385
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 386
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __sh__
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execve
+# define __NR_execve 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_time
+# define __NR_time 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_oldstat
+# define __NR_oldstat 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_mount
+# define __NR_mount 21
+# endif
+# ifndef __NR_umount
+# define __NR_umount 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_stime
+# define __NR_stime 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_oldfstat
+# define __NR_oldfstat 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_rename
+# define __NR_rename 38
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 39
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_brk
+# define __NR_brk 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 52
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 55
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 57
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 62
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 63
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 64
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 65
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 66
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 67
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 68
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 69
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 70
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 71
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 72
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 73
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 74
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 75
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 76
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 77
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 78
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 79
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 80
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 81
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 83
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 84
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 85
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 86
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 87
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 88
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 89
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 90
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 91
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 92
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 93
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 94
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 95
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 96
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 97
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 99
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 100
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 104
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 105
+# endif
+# ifndef __NR_stat
+# define __NR_stat 106
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 107
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 108
+# endif
+# ifndef __NR_olduname
+# define __NR_olduname 109
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 111
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 114
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 115
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 116
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 117
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 118
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 119
+# endif
+# ifndef __NR_clone
+# define __NR_clone 120
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 121
+# endif
+# ifndef __NR_uname
+# define __NR_uname 122
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush 123
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 124
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 125
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 126
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 128
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 129
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 131
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 132
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 133
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 134
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 135
+# endif
+# ifndef __NR_personality
+# define __NR_personality 136
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 138
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 139
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 140
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 141
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 142
+# endif
+# ifndef __NR_flock
+# define __NR_flock 143
+# endif
+# ifndef __NR_msync
+# define __NR_msync 144
+# endif
+# ifndef __NR_readv
+# define __NR_readv 145
+# endif
+# ifndef __NR_writev
+# define __NR_writev 146
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 147
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 148
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 149
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 150
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 151
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 152
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 153
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 154
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 155
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 156
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 157
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 158
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 159
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 160
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 161
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 162
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 163
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 164
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 165
+# endif
+# ifndef __NR_poll
+# define __NR_poll 168
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 169
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 170
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 171
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 172
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 173
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 174
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 175
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 176
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 177
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 178
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 179
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 180
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 181
+# endif
+# ifndef __NR_chown
+# define __NR_chown 182
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 183
+# endif
+# ifndef __NR_capget
+# define __NR_capget 184
+# endif
+# ifndef __NR_capset
+# define __NR_capset 185
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 186
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 187
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 190
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit 191
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 192
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 193
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 194
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 195
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 196
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 197
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 198
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 199
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 200
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 201
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 202
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 203
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 204
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 205
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 206
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 207
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 208
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 209
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 210
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 211
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 212
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 213
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 214
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 215
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 216
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 217
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 218
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 219
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 220
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 221
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 224
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 225
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 226
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 227
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 228
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 229
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 230
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 231
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 232
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 233
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 234
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 235
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 236
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 237
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 238
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 239
+# endif
+# ifndef __NR_futex
+# define __NR_futex 240
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 241
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 242
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 245
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 246
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 247
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 248
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 249
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 250
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 252
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 253
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 254
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 255
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 256
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 257
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 258
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 259
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 260
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 261
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 262
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 263
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 264
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 265
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 266
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 267
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 268
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 269
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 270
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 271
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 272
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 274
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 275
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 276
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 277
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 278
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 279
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 280
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 281
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 282
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 283
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 284
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 285
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 286
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 287
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 288
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 289
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 290
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 291
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 292
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 294
+# endif
+# ifndef __NR_openat
+# define __NR_openat 295
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 296
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 297
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 298
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 299
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 300
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 301
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 302
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 303
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 304
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 305
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 306
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 307
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 308
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 309
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 310
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 311
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 312
+# endif
+# ifndef __NR_splice
+# define __NR_splice 313
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 314
+# endif
+# ifndef __NR_tee
+# define __NR_tee 315
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 316
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 317
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 318
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 319
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 320
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 321
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 322
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 323
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 324
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 325
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 326
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 327
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 328
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 329
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 330
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 331
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 332
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 333
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 334
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 335
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 336
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 337
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 338
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 339
+# endif
+# ifndef __NR_socket
+# define __NR_socket 340
+# endif
+# ifndef __NR_bind
+# define __NR_bind 341
+# endif
+# ifndef __NR_connect
+# define __NR_connect 342
+# endif
+# ifndef __NR_listen
+# define __NR_listen 343
+# endif
+# ifndef __NR_accept
+# define __NR_accept 344
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 345
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 346
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 347
+# endif
+# ifndef __NR_send
+# define __NR_send 348
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 349
+# endif
+# ifndef __NR_recv
+# define __NR_recv 350
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 351
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 352
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 353
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 354
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 355
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 356
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 357
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 358
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 359
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 360
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 361
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 362
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 363
+# endif
+# ifndef __NR_setns
+# define __NR_setns 364
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 365
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 366
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 367
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 368
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 369
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 370
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 371
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 372
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 373
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 374
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 375
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 376
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 377
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 378
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 379
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 380
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 381
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 382
+# endif
+# ifndef __NR_statx
+# define __NR_statx 383
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 384
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 385
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 386
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 387
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#if defined(__sparc__) && defined(__arch64__)
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execv
+# define __NR_execv 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_chown
+# define __NR_chown 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_brk
+# define __NR_brk 17
+# endif
+# ifndef __NR_perfctr
+# define __NR_perfctr 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_capget
+# define __NR_capget 21
+# endif
+# ifndef __NR_capset
+# define __NR_capset 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 31
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_stat
+# define __NR_stat 38
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 39
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_memory_ordering
+# define __NR_memory_ordering 52
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 55
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 57
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 58
+# endif
+# ifndef __NR_execve
+# define __NR_execve 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 62
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 63
+# endif
+# ifndef __NR_getpagesize
+# define __NR_getpagesize 64
+# endif
+# ifndef __NR_msync
+# define __NR_msync 65
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 66
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 67
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 68
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 71
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 73
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 74
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 75
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 76
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 78
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 79
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 80
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 81
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 83
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 85
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 86
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 88
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 90
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 92
+# endif
+# ifndef __NR_select
+# define __NR_select 93
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 95
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 96
+# endif
+# ifndef __NR_socket
+# define __NR_socket 97
+# endif
+# ifndef __NR_connect
+# define __NR_connect 98
+# endif
+# ifndef __NR_accept
+# define __NR_accept 99
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 100
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 101
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 102
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 103
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 104
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 105
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 106
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 107
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 108
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 109
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 110
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 111
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 113
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 114
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 116
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 117
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 118
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 119
+# endif
+# ifndef __NR_readv
+# define __NR_readv 120
+# endif
+# ifndef __NR_writev
+# define __NR_writev 121
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 122
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 123
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 124
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 125
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 126
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 127
+# endif
+# ifndef __NR_rename
+# define __NR_rename 128
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 129
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 130
+# endif
+# ifndef __NR_flock
+# define __NR_flock 131
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 132
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 133
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 134
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 135
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 136
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 137
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 138
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 139
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 140
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 141
+# endif
+# ifndef __NR_futex
+# define __NR_futex 142
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 143
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 144
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 145
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 146
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 147
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read 148
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write 149
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 150
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 151
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 152
+# endif
+# ifndef __NR_poll
+# define __NR_poll 153
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 154
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 156
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 157
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 158
+# endif
+# ifndef __NR_umount
+# define __NR_umount 159
+# endif
+# ifndef __NR_sched_set_affinity
+# define __NR_sched_set_affinity 160
+# endif
+# ifndef __NR_sched_get_affinity
+# define __NR_sched_get_affinity 161
+# endif
+# ifndef __NR_getdomainname
+# define __NR_getdomainname 162
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 163
+# endif
+# ifndef __NR_utrap_install
+# define __NR_utrap_install 164
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 165
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 166
+# endif
+# ifndef __NR_mount
+# define __NR_mount 167
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 168
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 169
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 170
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 171
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 172
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 173
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 174
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 175
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 176
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 177
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 178
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 179
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 180
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 181
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 182
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 183
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 184
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 185
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 186
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 187
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 188
+# endif
+# ifndef __NR_uname
+# define __NR_uname 189
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 190
+# endif
+# ifndef __NR_personality
+# define __NR_personality 191
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 192
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 193
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 194
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 195
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 196
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 197
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 198
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 199
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 200
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 201
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 202
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 203
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 204
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 205
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 206
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 207
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 208
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 209
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 210
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 211
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 212
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 213
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 214
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 215
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 216
+# endif
+# ifndef __NR_clone
+# define __NR_clone 217
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 218
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 219
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 220
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 221
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 222
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 223
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 224
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 225
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 226
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 227
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 228
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 229
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 230
+# endif
+# ifndef __NR_splice
+# define __NR_splice 232
+# endif
+# ifndef __NR_stime
+# define __NR_stime 233
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 234
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 235
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 236
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 237
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 238
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 239
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 240
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 241
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 242
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 243
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 244
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 245
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 246
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 247
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 248
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 249
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 250
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 251
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 252
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 253
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 254
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 255
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 256
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 257
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 258
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 259
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 260
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 261
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 262
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 263
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 264
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 265
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 266
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 267
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 268
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 269
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 270
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 271
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 272
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 273
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 274
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 275
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 276
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 277
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 278
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 279
+# endif
+# ifndef __NR_tee
+# define __NR_tee 280
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 281
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 282
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 283
+# endif
+# ifndef __NR_openat
+# define __NR_openat 284
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 285
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 286
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 287
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 288
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 289
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 290
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 291
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 292
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 293
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 294
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 295
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 296
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 297
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 298
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 299
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 300
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 301
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 302
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 303
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 304
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 305
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 306
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 307
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 308
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 309
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 310
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 311
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 312
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 313
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 314
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 315
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 316
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 317
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 318
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 319
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 320
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 321
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 322
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 323
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 324
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 325
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 326
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 327
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 328
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 329
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 330
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 331
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 332
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 333
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 334
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 335
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 336
+# endif
+# ifndef __NR_setns
+# define __NR_setns 337
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 338
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 339
+# endif
+# ifndef __NR_kern_features
+# define __NR_kern_features 340
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 341
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 342
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 343
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 344
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 345
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 346
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 347
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 348
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 349
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 350
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 351
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 352
+# endif
+# ifndef __NR_bind
+# define __NR_bind 353
+# endif
+# ifndef __NR_listen
+# define __NR_listen 354
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 355
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 356
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 357
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 358
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 359
+# endif
+# ifndef __NR_statx
+# define __NR_statx 360
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 361
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 362
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 363
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 364
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 365
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 392
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#if defined(__sparc__) && !defined(__arch64__)
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 0
+# endif
+# ifndef __NR_exit
+# define __NR_exit 1
+# endif
+# ifndef __NR_fork
+# define __NR_fork 2
+# endif
+# ifndef __NR_read
+# define __NR_read 3
+# endif
+# ifndef __NR_write
+# define __NR_write 4
+# endif
+# ifndef __NR_open
+# define __NR_open 5
+# endif
+# ifndef __NR_close
+# define __NR_close 6
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 7
+# endif
+# ifndef __NR_creat
+# define __NR_creat 8
+# endif
+# ifndef __NR_link
+# define __NR_link 9
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 10
+# endif
+# ifndef __NR_execv
+# define __NR_execv 11
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 12
+# endif
+# ifndef __NR_chown
+# define __NR_chown 13
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 14
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 15
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 16
+# endif
+# ifndef __NR_brk
+# define __NR_brk 17
+# endif
+# ifndef __NR_perfctr
+# define __NR_perfctr 18
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 19
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 20
+# endif
+# ifndef __NR_capget
+# define __NR_capget 21
+# endif
+# ifndef __NR_capset
+# define __NR_capset 22
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 23
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 24
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 25
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 26
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 27
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 28
+# endif
+# ifndef __NR_pause
+# define __NR_pause 29
+# endif
+# ifndef __NR_utime
+# define __NR_utime 30
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 31
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 32
+# endif
+# ifndef __NR_access
+# define __NR_access 33
+# endif
+# ifndef __NR_nice
+# define __NR_nice 34
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 35
+# endif
+# ifndef __NR_sync
+# define __NR_sync 36
+# endif
+# ifndef __NR_kill
+# define __NR_kill 37
+# endif
+# ifndef __NR_stat
+# define __NR_stat 38
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 39
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 40
+# endif
+# ifndef __NR_dup
+# define __NR_dup 41
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 42
+# endif
+# ifndef __NR_times
+# define __NR_times 43
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 44
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 45
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 46
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 47
+# endif
+# ifndef __NR_signal
+# define __NR_signal 48
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 49
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 50
+# endif
+# ifndef __NR_acct
+# define __NR_acct 51
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 53
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 54
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 55
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 56
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 57
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 58
+# endif
+# ifndef __NR_execve
+# define __NR_execve 59
+# endif
+# ifndef __NR_umask
+# define __NR_umask 60
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 61
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 62
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 63
+# endif
+# ifndef __NR_getpagesize
+# define __NR_getpagesize 64
+# endif
+# ifndef __NR_msync
+# define __NR_msync 65
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 66
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 67
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 68
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 69
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 70
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 71
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 72
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 73
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 74
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 75
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 76
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 77
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 78
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 79
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 80
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 81
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 82
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 83
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 84
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 85
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 86
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 87
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 88
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 89
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 90
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 91
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 92
+# endif
+# ifndef __NR_select
+# define __NR_select 93
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 94
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 95
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 96
+# endif
+# ifndef __NR_socket
+# define __NR_socket 97
+# endif
+# ifndef __NR_connect
+# define __NR_connect 98
+# endif
+# ifndef __NR_accept
+# define __NR_accept 99
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 100
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 101
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 102
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 103
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 104
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 105
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 106
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 107
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 108
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 109
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 110
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 111
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 112
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 113
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 114
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 115
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 116
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 117
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 118
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 119
+# endif
+# ifndef __NR_readv
+# define __NR_readv 120
+# endif
+# ifndef __NR_writev
+# define __NR_writev 121
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 122
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 123
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 124
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 125
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 126
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 127
+# endif
+# ifndef __NR_rename
+# define __NR_rename 128
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 129
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 130
+# endif
+# ifndef __NR_flock
+# define __NR_flock 131
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 132
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 133
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 134
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 135
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 136
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 137
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 138
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 139
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 140
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 141
+# endif
+# ifndef __NR_futex
+# define __NR_futex 142
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 143
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 144
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 145
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 146
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 147
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read 148
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write 149
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 150
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 151
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 152
+# endif
+# ifndef __NR_poll
+# define __NR_poll 153
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 154
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 155
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 156
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 157
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 158
+# endif
+# ifndef __NR_umount
+# define __NR_umount 159
+# endif
+# ifndef __NR_sched_set_affinity
+# define __NR_sched_set_affinity 160
+# endif
+# ifndef __NR_sched_get_affinity
+# define __NR_sched_get_affinity 161
+# endif
+# ifndef __NR_getdomainname
+# define __NR_getdomainname 162
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 163
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 165
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 166
+# endif
+# ifndef __NR_mount
+# define __NR_mount 167
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 168
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 169
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 170
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 171
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 172
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 173
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 174
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 175
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 176
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 177
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 178
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 179
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 180
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 181
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 182
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending 183
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 184
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 185
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 186
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 187
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 188
+# endif
+# ifndef __NR_uname
+# define __NR_uname 189
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 190
+# endif
+# ifndef __NR_personality
+# define __NR_personality 191
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 192
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 193
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 194
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 195
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 196
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 197
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction 198
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask 199
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask 200
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend 201
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat 202
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 203
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir 204
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 205
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall 206
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 207
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 208
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 209
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 210
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 211
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid 212
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 213
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 214
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc 215
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn 216
+# endif
+# ifndef __NR_clone
+# define __NR_clone 217
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 218
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 219
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask 220
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 221
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 222
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 223
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 224
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush 225
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 226
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 227
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 228
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 229
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect 230
+# endif
+# ifndef __NR_time
+# define __NR_time 231
+# endif
+# ifndef __NR_splice
+# define __NR_splice 232
+# endif
+# ifndef __NR_stime
+# define __NR_stime 233
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 234
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 235
+# endif
+# ifndef __NR__llseek
+# define __NR__llseek 236
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 237
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 238
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 239
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 240
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 241
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 242
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 243
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 244
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 245
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 246
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 247
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 248
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 249
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 250
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 251
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 252
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 253
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 254
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 255
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 256
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 257
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 258
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 259
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 260
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 261
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 262
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 263
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 264
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 265
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 266
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 267
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 268
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 269
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 270
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 271
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 272
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 273
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 274
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 275
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 276
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 277
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 278
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 279
+# endif
+# ifndef __NR_tee
+# define __NR_tee 280
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 281
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 282
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 283
+# endif
+# ifndef __NR_openat
+# define __NR_openat 284
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 285
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 286
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 287
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 288
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 289
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 290
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 291
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 292
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 293
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 294
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 295
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 296
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 297
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 298
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 299
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 300
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 301
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 302
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 303
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 304
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 305
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 306
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 307
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 308
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 309
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 310
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 311
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 312
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 313
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 314
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 315
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 316
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 317
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 318
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 319
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 320
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 321
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 322
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 323
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 324
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 325
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 326
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 327
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 328
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 329
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 330
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 331
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 332
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 333
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 334
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 335
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 336
+# endif
+# ifndef __NR_setns
+# define __NR_setns 337
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 338
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 339
+# endif
+# ifndef __NR_kern_features
+# define __NR_kern_features 340
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 341
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 342
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 343
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 344
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 345
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 346
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 347
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 348
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 349
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 350
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 351
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 352
+# endif
+# ifndef __NR_bind
+# define __NR_bind 353
+# endif
+# ifndef __NR_listen
+# define __NR_listen 354
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 355
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 356
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 357
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 358
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 359
+# endif
+# ifndef __NR_statx
+# define __NR_statx 360
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 361
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 362
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 363
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 364
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 365
+# endif
+# ifndef __NR_semget
+# define __NR_semget 393
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 394
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 395
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 396
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 397
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 398
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 399
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 400
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 401
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 402
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 403
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 404
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 405
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 406
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 407
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 408
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 409
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 410
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 411
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 412
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 413
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 414
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 416
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 417
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 418
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 419
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 420
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 421
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 422
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 423
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+#endif
+
+
+#ifdef __x86_64__
+# ifndef __NR_read
+# define __NR_read 0
+# endif
+# ifndef __NR_write
+# define __NR_write 1
+# endif
+# ifndef __NR_open
+# define __NR_open 2
+# endif
+# ifndef __NR_close
+# define __NR_close 3
+# endif
+# ifndef __NR_stat
+# define __NR_stat 4
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat 5
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat 6
+# endif
+# ifndef __NR_poll
+# define __NR_poll 7
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek 8
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap 9
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect 10
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap 11
+# endif
+# ifndef __NR_brk
+# define __NR_brk 12
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 13
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask 14
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 15
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 16
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 17
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 18
+# endif
+# ifndef __NR_readv
+# define __NR_readv 19
+# endif
+# ifndef __NR_writev
+# define __NR_writev 20
+# endif
+# ifndef __NR_access
+# define __NR_access 21
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe 22
+# endif
+# ifndef __NR_select
+# define __NR_select 23
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield 24
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap 25
+# endif
+# ifndef __NR_msync
+# define __NR_msync 26
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore 27
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise 28
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget 29
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat 30
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl 31
+# endif
+# ifndef __NR_dup
+# define __NR_dup 32
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 33
+# endif
+# ifndef __NR_pause
+# define __NR_pause 34
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep 35
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer 36
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm 37
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer 38
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid 39
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile 40
+# endif
+# ifndef __NR_socket
+# define __NR_socket 41
+# endif
+# ifndef __NR_connect
+# define __NR_connect 42
+# endif
+# ifndef __NR_accept
+# define __NR_accept 43
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto 44
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 45
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 46
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 47
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown 48
+# endif
+# ifndef __NR_bind
+# define __NR_bind 49
+# endif
+# ifndef __NR_listen
+# define __NR_listen 50
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname 51
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername 52
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair 53
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 54
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 55
+# endif
+# ifndef __NR_clone
+# define __NR_clone 56
+# endif
+# ifndef __NR_fork
+# define __NR_fork 57
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork 58
+# endif
+# ifndef __NR_execve
+# define __NR_execve 59
+# endif
+# ifndef __NR_exit
+# define __NR_exit 60
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 61
+# endif
+# ifndef __NR_kill
+# define __NR_kill 62
+# endif
+# ifndef __NR_uname
+# define __NR_uname 63
+# endif
+# ifndef __NR_semget
+# define __NR_semget 64
+# endif
+# ifndef __NR_semop
+# define __NR_semop 65
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl 66
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt 67
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget 68
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd 69
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv 70
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl 71
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl 72
+# endif
+# ifndef __NR_flock
+# define __NR_flock 73
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync 74
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync 75
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate 76
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate 77
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents 78
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd 79
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir 80
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir 81
+# endif
+# ifndef __NR_rename
+# define __NR_rename 82
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir 83
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir 84
+# endif
+# ifndef __NR_creat
+# define __NR_creat 85
+# endif
+# ifndef __NR_link
+# define __NR_link 86
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink 87
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink 88
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink 89
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod 90
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod 91
+# endif
+# ifndef __NR_chown
+# define __NR_chown 92
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown 93
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown 94
+# endif
+# ifndef __NR_umask
+# define __NR_umask 95
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday 96
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit 97
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage 98
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo 99
+# endif
+# ifndef __NR_times
+# define __NR_times 100
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 101
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid 102
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog 103
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid 104
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid 105
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid 106
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid 107
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid 108
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid 109
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid 110
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp 111
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid 112
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid 113
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid 114
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups 115
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups 116
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid 117
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid 118
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid 119
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid 120
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid 121
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid 122
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid 123
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid 124
+# endif
+# ifndef __NR_capget
+# define __NR_capget 125
+# endif
+# ifndef __NR_capset
+# define __NR_capset 126
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 127
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 128
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 129
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend 130
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 131
+# endif
+# ifndef __NR_utime
+# define __NR_utime 132
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod 133
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib 134
+# endif
+# ifndef __NR_personality
+# define __NR_personality 135
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat 136
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs 137
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs 138
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs 139
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority 140
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority 141
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam 142
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam 143
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler 144
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler 145
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max 146
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min 147
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval 148
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock 149
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock 150
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall 151
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall 152
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup 153
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt 154
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root 155
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl 156
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl 157
+# endif
+# ifndef __NR_arch_prctl
+# define __NR_arch_prctl 158
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex 159
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit 160
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot 161
+# endif
+# ifndef __NR_sync
+# define __NR_sync 162
+# endif
+# ifndef __NR_acct
+# define __NR_acct 163
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday 164
+# endif
+# ifndef __NR_mount
+# define __NR_mount 165
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 166
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon 167
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff 168
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot 169
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname 170
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname 171
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl 172
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm 173
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module 174
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module 175
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module 176
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms 177
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module 178
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl 179
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl 180
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg 181
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg 182
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall 183
+# endif
+# ifndef __NR_tuxcall
+# define __NR_tuxcall 184
+# endif
+# ifndef __NR_security
+# define __NR_security 185
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid 186
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead 187
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr 188
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr 189
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr 190
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr 191
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr 192
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr 193
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr 194
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr 195
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr 196
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr 197
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr 198
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr 199
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill 200
+# endif
+# ifndef __NR_time
+# define __NR_time 201
+# endif
+# ifndef __NR_futex
+# define __NR_futex 202
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity 203
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity 204
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 205
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 206
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy 207
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents 208
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 209
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel 210
+# endif
+# ifndef __NR_get_thread_area
+# define __NR_get_thread_area 211
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie 212
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create 213
+# endif
+# ifndef __NR_epoll_ctl_old
+# define __NR_epoll_ctl_old 214
+# endif
+# ifndef __NR_epoll_wait_old
+# define __NR_epoll_wait_old 215
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages 216
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 217
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address 218
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall 219
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop 220
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 221
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 222
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime 223
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime 224
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun 225
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete 226
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime 227
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime 228
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres 229
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep 230
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group 231
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait 232
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl 233
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill 234
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes 235
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver 236
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind 237
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy 238
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy 239
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open 240
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink 241
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend 242
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive 243
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 244
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr 245
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 246
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 247
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key 248
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key 249
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl 250
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set 251
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get 252
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init 253
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch 254
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch 255
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages 256
+# endif
+# ifndef __NR_openat
+# define __NR_openat 257
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat 258
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat 259
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat 260
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat 261
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat 262
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat 263
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat 264
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat 265
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat 266
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat 267
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat 268
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat 269
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 270
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll 271
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare 272
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 273
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 274
+# endif
+# ifndef __NR_splice
+# define __NR_splice 275
+# endif
+# ifndef __NR_tee
+# define __NR_tee 276
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range 277
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 278
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 279
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat 280
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait 281
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd 282
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create 283
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd 284
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate 285
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime 286
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime 287
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 288
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 289
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 290
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 291
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 292
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 293
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 294
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 295
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 296
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 297
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open 298
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 299
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 300
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 301
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 302
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at 303
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at 304
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime 305
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs 306
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 307
+# endif
+# ifndef __NR_setns
+# define __NR_setns 308
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu 309
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 310
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 311
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp 312
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module 313
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr 314
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr 315
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 316
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp 317
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom 318
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create 319
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load 320
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf 321
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 322
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd 323
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier 324
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 325
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range 326
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 327
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 328
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect 329
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc 330
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free 331
+# endif
+# ifndef __NR_statx
+# define __NR_statx 332
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents 333
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq 334
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal 424
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup 425
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter 426
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register 427
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree 428
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount 429
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen 430
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig 431
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount 432
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick 433
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open 434
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 435
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 437
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd 438
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction 512
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn 513
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl 514
+# endif
+# ifndef __NR_readv
+# define __NR_readv 515
+# endif
+# ifndef __NR_writev
+# define __NR_writev 516
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom 517
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg 518
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg 519
+# endif
+# ifndef __NR_execve
+# define __NR_execve 520
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace 521
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending 522
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait 523
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo 524
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack 525
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create 526
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify 527
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load 528
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid 529
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list 530
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list 531
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice 532
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages 533
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv 534
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev 535
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo 536
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg 537
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg 538
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv 539
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev 540
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt 541
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt 542
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup 543
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit 544
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat 545
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 546
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 547
+# endif
+#endif
+
+
+/* Common stubs */
+# ifndef __NR__llseek
+# define __NR__llseek __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR__newselect
+# define __NR__newselect __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR__sysctl
+# define __NR__sysctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_accept
+# define __NR_accept __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_accept4
+# define __NR_accept4 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_access
+# define __NR_access __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_acct
+# define __NR_acct __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_add_key
+# define __NR_add_key __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_adjtimex
+# define __NR_adjtimex __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_afs_syscall
+# define __NR_afs_syscall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_alarm
+# define __NR_alarm __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arc_gettls
+# define __NR_arc_gettls __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arc_settls
+# define __NR_arc_settls __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arc_usr_cmpxchg
+# define __NR_arc_usr_cmpxchg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arch_prctl
+# define __NR_arch_prctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arm_fadvise64_64
+# define __NR_arm_fadvise64_64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_arm_sync_file_range
+# define __NR_arm_sync_file_range __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_bdflush
+# define __NR_bdflush __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_bind
+# define __NR_bind __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_bpf
+# define __NR_bpf __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_break
+# define __NR_break __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_brk
+# define __NR_brk __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_cachectl
+# define __NR_cachectl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_cacheflush
+# define __NR_cacheflush __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_capget
+# define __NR_capget __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_capset
+# define __NR_capset __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_chdir
+# define __NR_chdir __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_chmod
+# define __NR_chmod __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_chown
+# define __NR_chown __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_chown32
+# define __NR_chown32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_chroot
+# define __NR_chroot __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_adjtime
+# define __NR_clock_adjtime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_adjtime64
+# define __NR_clock_adjtime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_getres
+# define __NR_clock_getres __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_getres_time64
+# define __NR_clock_getres_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_gettime
+# define __NR_clock_gettime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_gettime64
+# define __NR_clock_gettime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_nanosleep
+# define __NR_clock_nanosleep __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_nanosleep_time64
+# define __NR_clock_nanosleep_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_settime
+# define __NR_clock_settime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clock_settime64
+# define __NR_clock_settime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clone
+# define __NR_clone __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clone2
+# define __NR_clone2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_clone3
+# define __NR_clone3 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_close
+# define __NR_close __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_connect
+# define __NR_connect __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_copy_file_range
+# define __NR_copy_file_range __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_creat
+# define __NR_creat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_create_module
+# define __NR_create_module __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_delete_module
+# define __NR_delete_module __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_dup
+# define __NR_dup __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_dup2
+# define __NR_dup2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_dup3
+# define __NR_dup3 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_create
+# define __NR_epoll_create __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_create1
+# define __NR_epoll_create1 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_ctl
+# define __NR_epoll_ctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_ctl_old
+# define __NR_epoll_ctl_old __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_pwait
+# define __NR_epoll_pwait __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_wait
+# define __NR_epoll_wait __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_epoll_wait_old
+# define __NR_epoll_wait_old __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_eventfd
+# define __NR_eventfd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_eventfd2
+# define __NR_eventfd2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_execv
+# define __NR_execv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_execve
+# define __NR_execve __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_execveat
+# define __NR_execveat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_exit
+# define __NR_exit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_exit_group
+# define __NR_exit_group __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_faccessat
+# define __NR_faccessat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fadvise64
+# define __NR_fadvise64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fadvise64_64
+# define __NR_fadvise64_64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fallocate
+# define __NR_fallocate __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchdir
+# define __NR_fchdir __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchmod
+# define __NR_fchmod __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchmodat
+# define __NR_fchmodat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchown
+# define __NR_fchown __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchown32
+# define __NR_fchown32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fchownat
+# define __NR_fchownat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fcntl
+# define __NR_fcntl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fcntl64
+# define __NR_fcntl64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fdatasync
+# define __NR_fdatasync __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fgetxattr
+# define __NR_fgetxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_finit_module
+# define __NR_finit_module __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_flistxattr
+# define __NR_flistxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_flock
+# define __NR_flock __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fork
+# define __NR_fork __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fremovexattr
+# define __NR_fremovexattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fsconfig
+# define __NR_fsconfig __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fsetxattr
+# define __NR_fsetxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fsmount
+# define __NR_fsmount __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fsopen
+# define __NR_fsopen __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fspick
+# define __NR_fspick __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstat
+# define __NR_fstat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstat64
+# define __NR_fstat64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstatat
+# define __NR_fstatat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstatat64
+# define __NR_fstatat64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstatfs
+# define __NR_fstatfs __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fstatfs64
+# define __NR_fstatfs64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_fsync
+# define __NR_fsync __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ftime
+# define __NR_ftime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ftruncate
+# define __NR_ftruncate __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ftruncate64
+# define __NR_ftruncate64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_futex
+# define __NR_futex __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_futex_time64
+# define __NR_futex_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_futimesat
+# define __NR_futimesat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_get_kernel_syms
+# define __NR_get_kernel_syms __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_get_mempolicy
+# define __NR_get_mempolicy __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_get_robust_list
+# define __NR_get_robust_list __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_get_thread_area
+# define __NR_get_thread_area __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getcpu
+# define __NR_getcpu __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getcwd
+# define __NR_getcwd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getdents
+# define __NR_getdents __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getdents64
+# define __NR_getdents64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getdomainname
+# define __NR_getdomainname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getegid
+# define __NR_getegid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getegid32
+# define __NR_getegid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_geteuid
+# define __NR_geteuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_geteuid32
+# define __NR_geteuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getgid
+# define __NR_getgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getgid32
+# define __NR_getgid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getgroups
+# define __NR_getgroups __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getgroups32
+# define __NR_getgroups32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getitimer
+# define __NR_getitimer __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpagesize
+# define __NR_getpagesize __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpeername
+# define __NR_getpeername __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpgid
+# define __NR_getpgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpgrp
+# define __NR_getpgrp __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpid
+# define __NR_getpid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpmsg
+# define __NR_getpmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getppid
+# define __NR_getppid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getpriority
+# define __NR_getpriority __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getrandom
+# define __NR_getrandom __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getresgid
+# define __NR_getresgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getresgid32
+# define __NR_getresgid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getresuid
+# define __NR_getresuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getresuid32
+# define __NR_getresuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getrlimit
+# define __NR_getrlimit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getrusage
+# define __NR_getrusage __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getsid
+# define __NR_getsid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getsockname
+# define __NR_getsockname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getsockopt
+# define __NR_getsockopt __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_gettid
+# define __NR_gettid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_gettimeofday
+# define __NR_gettimeofday __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getuid
+# define __NR_getuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getuid32
+# define __NR_getuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getunwind
+# define __NR_getunwind __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_getxattr
+# define __NR_getxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_gtty
+# define __NR_gtty __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_idle
+# define __NR_idle __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_init_module
+# define __NR_init_module __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_inotify_add_watch
+# define __NR_inotify_add_watch __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_inotify_init
+# define __NR_inotify_init __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_inotify_init1
+# define __NR_inotify_init1 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_inotify_rm_watch
+# define __NR_inotify_rm_watch __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_cancel
+# define __NR_io_cancel __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_destroy
+# define __NR_io_destroy __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_getevents
+# define __NR_io_getevents __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_pgetevents
+# define __NR_io_pgetevents __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_pgetevents_time64
+# define __NR_io_pgetevents_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_setup
+# define __NR_io_setup __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_submit
+# define __NR_io_submit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_uring_enter
+# define __NR_io_uring_enter __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_uring_register
+# define __NR_io_uring_register __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_io_uring_setup
+# define __NR_io_uring_setup __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ioctl
+# define __NR_ioctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ioperm
+# define __NR_ioperm __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_iopl
+# define __NR_iopl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ioprio_get
+# define __NR_ioprio_get __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ioprio_set
+# define __NR_ioprio_set __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ipc
+# define __NR_ipc __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_kcmp
+# define __NR_kcmp __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_kern_features
+# define __NR_kern_features __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_kexec_file_load
+# define __NR_kexec_file_load __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_kexec_load
+# define __NR_kexec_load __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_keyctl
+# define __NR_keyctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_kill
+# define __NR_kill __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lchown
+# define __NR_lchown __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lchown32
+# define __NR_lchown32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lgetxattr
+# define __NR_lgetxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_link
+# define __NR_link __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_linkat
+# define __NR_linkat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_listen
+# define __NR_listen __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_listxattr
+# define __NR_listxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_llistxattr
+# define __NR_llistxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lock
+# define __NR_lock __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lookup_dcookie
+# define __NR_lookup_dcookie __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lremovexattr
+# define __NR_lremovexattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lseek
+# define __NR_lseek __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lsetxattr
+# define __NR_lsetxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lstat
+# define __NR_lstat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_lstat64
+# define __NR_lstat64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_madvise
+# define __NR_madvise __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_madvise1
+# define __NR_madvise1 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mbind
+# define __NR_mbind __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_membarrier
+# define __NR_membarrier __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_memfd_create
+# define __NR_memfd_create __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_memory_ordering
+# define __NR_memory_ordering __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_migrate_pages
+# define __NR_migrate_pages __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mincore
+# define __NR_mincore __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mkdir
+# define __NR_mkdir __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mkdirat
+# define __NR_mkdirat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mknod
+# define __NR_mknod __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mknodat
+# define __NR_mknodat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mlock
+# define __NR_mlock __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mlock2
+# define __NR_mlock2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mlockall
+# define __NR_mlockall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mmap
+# define __NR_mmap __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mmap2
+# define __NR_mmap2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_modify_ldt
+# define __NR_modify_ldt __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mount
+# define __NR_mount __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_move_mount
+# define __NR_move_mount __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_move_pages
+# define __NR_move_pages __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mprotect
+# define __NR_mprotect __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mpx
+# define __NR_mpx __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_getsetattr
+# define __NR_mq_getsetattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_notify
+# define __NR_mq_notify __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_open
+# define __NR_mq_open __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_timedreceive
+# define __NR_mq_timedreceive __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_timedreceive_time64
+# define __NR_mq_timedreceive_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_timedsend
+# define __NR_mq_timedsend __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_timedsend_time64
+# define __NR_mq_timedsend_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mq_unlink
+# define __NR_mq_unlink __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_mremap
+# define __NR_mremap __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_msgctl
+# define __NR_msgctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_msgget
+# define __NR_msgget __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_msgrcv
+# define __NR_msgrcv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_msgsnd
+# define __NR_msgsnd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_msync
+# define __NR_msync __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_multiplexer
+# define __NR_multiplexer __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_munlock
+# define __NR_munlock __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_munlockall
+# define __NR_munlockall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_munmap
+# define __NR_munmap __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_name_to_handle_at
+# define __NR_name_to_handle_at __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_nanosleep
+# define __NR_nanosleep __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_newfstatat
+# define __NR_newfstatat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_nfsservctl
+# define __NR_nfsservctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ni_syscall
+# define __NR_ni_syscall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_nice
+# define __NR_nice __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_old_getpagesize
+# define __NR_old_getpagesize __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_oldfstat
+# define __NR_oldfstat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_oldlstat
+# define __NR_oldlstat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_oldolduname
+# define __NR_oldolduname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_oldstat
+# define __NR_oldstat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_olduname
+# define __NR_olduname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_open
+# define __NR_open __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_open_by_handle_at
+# define __NR_open_by_handle_at __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_open_tree
+# define __NR_open_tree __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_openat
+# define __NR_openat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_openat2
+# define __NR_openat2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pause
+# define __NR_pause __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pciconfig_iobase
+# define __NR_pciconfig_iobase __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pciconfig_read
+# define __NR_pciconfig_read __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pciconfig_write
+# define __NR_pciconfig_write __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_perf_event_open
+# define __NR_perf_event_open __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_perfctr
+# define __NR_perfctr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_perfmonctl
+# define __NR_perfmonctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_personality
+# define __NR_personality __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pidfd_getfd
+# define __NR_pidfd_getfd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pidfd_open
+# define __NR_pidfd_open __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pidfd_send_signal
+# define __NR_pidfd_send_signal __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pipe
+# define __NR_pipe __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pipe2
+# define __NR_pipe2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pivot_root
+# define __NR_pivot_root __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pkey_alloc
+# define __NR_pkey_alloc __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pkey_free
+# define __NR_pkey_free __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pkey_mprotect
+# define __NR_pkey_mprotect __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_poll
+# define __NR_poll __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ppoll
+# define __NR_ppoll __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ppoll_time64
+# define __NR_ppoll_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_prctl
+# define __NR_prctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pread64
+# define __NR_pread64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_preadv
+# define __NR_preadv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_preadv2
+# define __NR_preadv2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_prlimit64
+# define __NR_prlimit64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_process_vm_readv
+# define __NR_process_vm_readv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_process_vm_writev
+# define __NR_process_vm_writev __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_prof
+# define __NR_prof __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_profil
+# define __NR_profil __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pselect6
+# define __NR_pselect6 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ptrace
+# define __NR_ptrace __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_putpmsg
+# define __NR_putpmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pwrite64
+# define __NR_pwrite64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pwritev
+# define __NR_pwritev __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_pwritev2
+# define __NR_pwritev2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_query_module
+# define __NR_query_module __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_quotactl
+# define __NR_quotactl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_read
+# define __NR_read __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_readahead
+# define __NR_readahead __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_readdir
+# define __NR_readdir __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_readlink
+# define __NR_readlink __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_readlinkat
+# define __NR_readlinkat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_readv
+# define __NR_readv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_reboot
+# define __NR_reboot __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_recv
+# define __NR_recv __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_recvfrom
+# define __NR_recvfrom __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_recvmmsg
+# define __NR_recvmmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_recvmmsg_time64
+# define __NR_recvmmsg_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_recvmsg
+# define __NR_recvmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_remap_file_pages
+# define __NR_remap_file_pages __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_removexattr
+# define __NR_removexattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rename
+# define __NR_rename __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_renameat
+# define __NR_renameat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_renameat2
+# define __NR_renameat2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_request_key
+# define __NR_request_key __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_reserved177
+# define __NR_reserved177 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_reserved193
+# define __NR_reserved193 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_reserved221
+# define __NR_reserved221 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_reserved82
+# define __NR_reserved82 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_restart_syscall
+# define __NR_restart_syscall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rmdir
+# define __NR_rmdir __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rseq
+# define __NR_rseq __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigaction
+# define __NR_rt_sigaction __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigpending
+# define __NR_rt_sigpending __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigprocmask
+# define __NR_rt_sigprocmask __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigqueueinfo
+# define __NR_rt_sigqueueinfo __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigreturn
+# define __NR_rt_sigreturn __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigsuspend
+# define __NR_rt_sigsuspend __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigtimedwait
+# define __NR_rt_sigtimedwait __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_sigtimedwait_time64
+# define __NR_rt_sigtimedwait_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rt_tgsigqueueinfo
+# define __NR_rt_tgsigqueueinfo __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_rtas
+# define __NR_rtas __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_s390_guarded_storage
+# define __NR_s390_guarded_storage __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_s390_pci_mmio_read
+# define __NR_s390_pci_mmio_read __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_s390_pci_mmio_write
+# define __NR_s390_pci_mmio_write __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_s390_runtime_instr
+# define __NR_s390_runtime_instr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_s390_sthyi
+# define __NR_s390_sthyi __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_get_affinity
+# define __NR_sched_get_affinity __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_get_priority_max
+# define __NR_sched_get_priority_max __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_get_priority_min
+# define __NR_sched_get_priority_min __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_getaffinity
+# define __NR_sched_getaffinity __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_getattr
+# define __NR_sched_getattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_getparam
+# define __NR_sched_getparam __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_getscheduler
+# define __NR_sched_getscheduler __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_rr_get_interval
+# define __NR_sched_rr_get_interval __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_rr_get_interval_time64
+# define __NR_sched_rr_get_interval_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_set_affinity
+# define __NR_sched_set_affinity __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_setaffinity
+# define __NR_sched_setaffinity __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_setattr
+# define __NR_sched_setattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_setparam
+# define __NR_sched_setparam __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_setscheduler
+# define __NR_sched_setscheduler __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sched_yield
+# define __NR_sched_yield __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_seccomp
+# define __NR_seccomp __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_security
+# define __NR_security __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_select
+# define __NR_select __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_semctl
+# define __NR_semctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_semget
+# define __NR_semget __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_semop
+# define __NR_semop __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_semtimedop
+# define __NR_semtimedop __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_semtimedop_time64
+# define __NR_semtimedop_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_send
+# define __NR_send __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sendfile
+# define __NR_sendfile __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sendfile64
+# define __NR_sendfile64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sendmmsg
+# define __NR_sendmmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sendmsg
+# define __NR_sendmsg __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sendto
+# define __NR_sendto __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_set_mempolicy
+# define __NR_set_mempolicy __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_set_robust_list
+# define __NR_set_robust_list __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_set_tid_address
+# define __NR_set_tid_address __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setdomainname
+# define __NR_setdomainname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setfsgid
+# define __NR_setfsgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setfsgid32
+# define __NR_setfsgid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setfsuid
+# define __NR_setfsuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setfsuid32
+# define __NR_setfsuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setgid
+# define __NR_setgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setgid32
+# define __NR_setgid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setgroups
+# define __NR_setgroups __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setgroups32
+# define __NR_setgroups32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sethostname
+# define __NR_sethostname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setitimer
+# define __NR_setitimer __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setns
+# define __NR_setns __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setpgid
+# define __NR_setpgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setpriority
+# define __NR_setpriority __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setregid
+# define __NR_setregid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setregid32
+# define __NR_setregid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setresgid
+# define __NR_setresgid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setresgid32
+# define __NR_setresgid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setresuid
+# define __NR_setresuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setresuid32
+# define __NR_setresuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setreuid
+# define __NR_setreuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setreuid32
+# define __NR_setreuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setrlimit
+# define __NR_setrlimit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setsid
+# define __NR_setsid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setsockopt
+# define __NR_setsockopt __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_settimeofday
+# define __NR_settimeofday __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setuid
+# define __NR_setuid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setuid32
+# define __NR_setuid32 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_setxattr
+# define __NR_setxattr __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sgetmask
+# define __NR_sgetmask __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_shmat
+# define __NR_shmat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_shmctl
+# define __NR_shmctl __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_shmdt
+# define __NR_shmdt __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_shmget
+# define __NR_shmget __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_shutdown
+# define __NR_shutdown __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigaction
+# define __NR_sigaction __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigaltstack
+# define __NR_sigaltstack __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_signal
+# define __NR_signal __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_signalfd
+# define __NR_signalfd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_signalfd4
+# define __NR_signalfd4 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigpending
+# define __NR_sigpending __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigprocmask
+# define __NR_sigprocmask __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigreturn
+# define __NR_sigreturn __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sigsuspend
+# define __NR_sigsuspend __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_socket
+# define __NR_socket __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_socketcall
+# define __NR_socketcall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_socketpair
+# define __NR_socketpair __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_splice
+# define __NR_splice __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_spu_create
+# define __NR_spu_create __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_spu_run
+# define __NR_spu_run __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ssetmask
+# define __NR_ssetmask __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_stat
+# define __NR_stat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_stat64
+# define __NR_stat64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_statfs
+# define __NR_statfs __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_statfs64
+# define __NR_statfs64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_statx
+# define __NR_statx __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_stime
+# define __NR_stime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_stty
+# define __NR_stty __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_subpage_prot
+# define __NR_subpage_prot __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_swapcontext
+# define __NR_swapcontext __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_swapoff
+# define __NR_swapoff __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_swapon
+# define __NR_swapon __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_switch_endian
+# define __NR_switch_endian __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_symlink
+# define __NR_symlink __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_symlinkat
+# define __NR_symlinkat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sync
+# define __NR_sync __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sync_file_range
+# define __NR_sync_file_range __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sync_file_range2
+# define __NR_sync_file_range2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_syncfs
+# define __NR_syncfs __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sys_debug_setcontext
+# define __NR_sys_debug_setcontext __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_syscall
+# define __NR_syscall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sysfs
+# define __NR_sysfs __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sysinfo
+# define __NR_sysinfo __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_syslog
+# define __NR_syslog __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_sysmips
+# define __NR_sysmips __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_tee
+# define __NR_tee __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_tgkill
+# define __NR_tgkill __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_time
+# define __NR_time __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_create
+# define __NR_timer_create __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_delete
+# define __NR_timer_delete __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_getoverrun
+# define __NR_timer_getoverrun __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_gettime
+# define __NR_timer_gettime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_gettime64
+# define __NR_timer_gettime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_settime
+# define __NR_timer_settime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timer_settime64
+# define __NR_timer_settime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd
+# define __NR_timerfd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd_create
+# define __NR_timerfd_create __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd_gettime
+# define __NR_timerfd_gettime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd_gettime64
+# define __NR_timerfd_gettime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd_settime
+# define __NR_timerfd_settime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_timerfd_settime64
+# define __NR_timerfd_settime64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_times
+# define __NR_times __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_tkill
+# define __NR_tkill __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_truncate
+# define __NR_truncate __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_truncate64
+# define __NR_truncate64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_tuxcall
+# define __NR_tuxcall __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ugetrlimit
+# define __NR_ugetrlimit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ulimit
+# define __NR_ulimit __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_umask
+# define __NR_umask __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_umount
+# define __NR_umount __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_umount2
+# define __NR_umount2 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_uname
+# define __NR_uname __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unlink
+# define __NR_unlink __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unlinkat
+# define __NR_unlinkat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unshare
+# define __NR_unshare __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused109
+# define __NR_unused109 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused150
+# define __NR_unused150 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused18
+# define __NR_unused18 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused28
+# define __NR_unused28 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused59
+# define __NR_unused59 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_unused84
+# define __NR_unused84 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_uselib
+# define __NR_uselib __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_userfaultfd
+# define __NR_userfaultfd __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_ustat
+# define __NR_ustat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_utime
+# define __NR_utime __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_utimensat
+# define __NR_utimensat __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_utimensat_time64
+# define __NR_utimensat_time64 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_utimes
+# define __NR_utimes __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_utrap_install
+# define __NR_utrap_install __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vfork
+# define __NR_vfork __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vhangup
+# define __NR_vhangup __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vm86
+# define __NR_vm86 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vm86old
+# define __NR_vm86old __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vmsplice
+# define __NR_vmsplice __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_vserver
+# define __NR_vserver __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_wait4
+# define __NR_wait4 __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_waitid
+# define __NR_waitid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_waitpid
+# define __NR_waitpid __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_write
+# define __NR_write __LTP__NR_INVALID_SYSCALL
+# endif
+# ifndef __NR_writev
+# define __NR_writev __LTP__NR_INVALID_SYSCALL
+# endif
+#endif
diff --git a/src/kernel/tests/include/lapi/tcp.h b/src/kernel/tests/include/lapi/tcp.h
new file mode 100644
index 0000000..bb98f28
--- /dev/null
+++ b/src/kernel/tests/include/lapi/tcp.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef LAPI_TCP_H__
+#define LAPI_TCP_H__
+
+#include <netinet/tcp.h>
+
+#ifndef TCP_FASTOPEN
+# define TCP_FASTOPEN 23
+#endif
+
+#ifndef TCP_FASTOPEN_CONNECT
+# define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect */
+#endif
+
+#endif /* LAPI_TCP_H__ */
diff --git a/src/kernel/tests/include/lapi/tee.h b/src/kernel/tests/include/lapi/tee.h
new file mode 100644
index 0000000..422e811
--- /dev/null
+++ b/src/kernel/tests/include/lapi/tee.h
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ */
+
+#ifndef TEE_H
+#define TEE_H
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#if !defined(HAVE_TEE)
+ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags)
+{
+ return tst_syscall(__NR_tee, fd_in, fd_out, len, flags);
+}
+#endif
+
+#endif /* TEE_H */
diff --git a/src/kernel/tests/include/lapi/termbits.h b/src/kernel/tests/include/lapi/termbits.h
new file mode 100644
index 0000000..d79da08
--- /dev/null
+++ b/src/kernel/tests/include/lapi/termbits.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Linux Test Project
+ */
+
+#ifndef LAPI_TERMBITS_H__
+#define LAPI_TERMBITS_H__
+
+#ifndef EXTPROC
+# define EXTPROC 0200000
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/timerfd.h b/src/kernel/tests/include/lapi/timerfd.h
new file mode 100644
index 0000000..50e0972
--- /dev/null
+++ b/src/kernel/tests/include/lapi/timerfd.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Fujitsu Ltd.
+ */
+
+#ifndef TIMERFD_H
+#define TIMERFD_H
+
+#include <time.h>
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifdef HAVE_SYS_TIMERFD_H
+#include <sys/timerfd.h>
+#endif
+
+#if !defined(HAVE_TIMERFD_CREATE)
+int timerfd_create(int clockid, int flags)
+{
+ return ltp_syscall(__NR_timerfd_create, clockid, flags);
+}
+#endif
+
+#if !defined(HAVE_TIMERFD_GETTIME)
+int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,
+ struct itimerspec *old_value)
+{
+ return ltp_syscall(__NR_timerfd_settime, fd, flags, new_value,
+ old_value);
+}
+#endif
+
+#if !defined(HAVE_TIMERFD_SETTIME)
+int timerfd_gettime(int fd, struct itimerspec *curr_value)
+{
+ return ltp_syscall(__NR_timerfd_gettime, fd, curr_value);
+}
+#endif
+
+#endif /* TIMERFD_H */
diff --git a/src/kernel/tests/include/lapi/timex.h b/src/kernel/tests/include/lapi/timex.h
new file mode 100644
index 0000000..c2c9e4d
--- /dev/null
+++ b/src/kernel/tests/include/lapi/timex.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+
+#ifndef LAPI_TIMEX_H__
+# define LAPI_TIMEX_H__
+
+#define ADJ_ALL (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | \
+ ADJ_ESTERROR | ADJ_STATUS | ADJ_TIMECONST | \
+ ADJ_TICK)
+
+#ifndef ADJ_OFFSET_SS_READ
+# define ADJ_OFFSET_SS_READ 0xa001
+#endif
+
+#ifndef ADJ_NANO
+# define ADJ_NANO 0x2000
+#endif
+
+#ifndef STA_NANO
+# define STA_NANO 0x2000
+#endif
+
+#ifndef ADJ_MICRO
+# define ADJ_MICRO 0x1000
+#endif
+
+#endif/* LAPI_TIMEX_H__ */
diff --git a/src/kernel/tests/include/lapi/tty.h b/src/kernel/tests/include/lapi/tty.h
new file mode 100644
index 0000000..6122145
--- /dev/null
+++ b/src/kernel/tests/include/lapi/tty.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef LAPI_TTY_H
+#define LAPI_TTY_H
+
+#ifdef HAVE_LINUX_TTY_H
+# include <linux/tty.h>
+#endif
+
+#ifndef N_HDLC
+# define N_HDLC 13
+#endif
+
+#ifndef N_SLCAN
+# define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
+#endif
+
+#endif /* LAPI_TTY_H */
diff --git a/src/kernel/tests/include/lapi/udp.h b/src/kernel/tests/include/lapi/udp.h
new file mode 100644
index 0000000..5c73dd3
--- /dev/null
+++ b/src/kernel/tests/include/lapi/udp.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Oracle and/or its affiliates.
+ */
+
+#ifndef LAPI_UDP_H__
+#define LAPI_UDP_H__
+
+#include <netinet/udp.h>
+
+#ifndef UDPLITE_SEND_CSCOV
+# define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */
+#endif
+#ifndef UDPLITE_RECV_CSCOV
+# define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */
+#endif
+
+#endif /* LAPI_UDP_H__ */
diff --git a/src/kernel/tests/include/lapi/ustat.h b/src/kernel/tests/include/lapi/ustat.h
new file mode 100644
index 0000000..98633e7
--- /dev/null
+++ b/src/kernel/tests/include/lapi/ustat.h
@@ -0,0 +1,22 @@
+//SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef LAPI_USTAT_H
+#define LAPI_USTAT_H
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_USTAT_H
+# include <sys/ustat.h>
+#elif HAVE_LINUX_TYPES_H
+# include <linux/types.h>
+struct ustat {
+ __kernel_daddr_t f_tfree;
+ ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+#endif
+
+#endif /* LAPI_USTAT_H */
diff --git a/src/kernel/tests/include/lapi/utime.h b/src/kernel/tests/include/lapi/utime.h
new file mode 100644
index 0000000..dbfaa55
--- /dev/null
+++ b/src/kernel/tests/include/lapi/utime.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ */
+
+#ifndef __UTIME_H__
+
+#ifndef UTIME_NOW
+# define UTIME_NOW ((1l << 30) - 1l)
+#endif
+
+#ifndef UTIME_OMIT
+# define UTIME_OMIT ((1l << 30) - 2l)
+#endif
+
+#endif /* __UTIME_H__ */
diff --git a/src/kernel/tests/include/lapi/utsname.h b/src/kernel/tests/include/lapi/utsname.h
new file mode 100644
index 0000000..6209eac
--- /dev/null
+++ b/src/kernel/tests/include/lapi/utsname.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Petr Vorel <petr.vorel@gmail.com>
+ */
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+#ifndef _UTSNAME_LENGTH
+# define _UTSNAME_LENGTH 65
+#endif
+
+#ifndef _UTSNAME_DOMAIN_LENGTH
+# define _UTSNAME_DOMAIN_LENGTH _UTSNAME_LENGTH
+#endif
diff --git a/src/kernel/tests/include/lapi/vmsplice.h b/src/kernel/tests/include/lapi/vmsplice.h
new file mode 100644
index 0000000..ba0fcca
--- /dev/null
+++ b/src/kernel/tests/include/lapi/vmsplice.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) International Business Machines Corp., 2007
+ * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef VMSPLICE_H
+#define VMSPLICE_H
+
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#include "lapi/iovec.h"
+
+#if !defined(HAVE_VMSPLICE)
+ssize_t vmsplice(int fd, const struct iovec *iov,
+ unsigned long nr_segs, unsigned int flags)
+{
+ return tst_syscall(__NR_vmsplice, fd, iov, nr_segs, flags);
+}
+#endif
+
+#endif /* VMSPLICE_H */
diff --git a/src/kernel/tests/include/lapi/xfrm.h b/src/kernel/tests/include/lapi/xfrm.h
new file mode 100644
index 0000000..d905120
--- /dev/null
+++ b/src/kernel/tests/include/lapi/xfrm.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Linux Test Project
+ */
+
+#ifndef LAPI_XFRM_H__
+#define LAPI_XFRM_H__
+
+#ifndef XFRMNLGRP_NONE
+# define XFRMNLGRP_NONE 0
+#endif
+
+#ifndef XFRM_MSG_GETPOLICY
+# define XFRM_MSG_GETPOLICY 21
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/lapi/xloop.h b/src/kernel/tests/include/lapi/xloop.h
new file mode 100644
index 0000000..769d1f0
--- /dev/null
+++ b/src/kernel/tests/include/lapi/xloop.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ */
+#ifndef LAPI_LOOP_H
+#define LAPI_LOOP_H
+
+#include "config.h"
+#include <linux/types.h>
+#include <uapi_xloop.h>
+
+#ifndef LO_FLAGS_PARTSCAN
+# define LO_FLAGS_PARTSCAN 8
+#endif
+
+#ifndef LO_FLAGS_DIRECT_IO
+# define LO_FLAGS_DIRECT_IO 16
+#endif
+
+#ifndef LOOP_SET_CAPACITY
+# define LOOP_SET_CAPACITY 0x4C07
+#endif
+
+#ifndef LOOP_SET_DIRECT_IO
+# define LOOP_SET_DIRECT_IO 0x4C08
+#endif
+
+#ifndef LOOP_SET_BLOCK_SIZE
+# define LOOP_SET_BLOCK_SIZE 0x4C09
+#endif
+
+#ifndef LOOP_CONFIGURE
+# define LOOP_CONFIGURE 0x4C0A
+#endif
+
+#ifndef HAVE_STRUCT_LOOP_CONFIG
+/*
+ * struct loop_config - Complete configuration for a loop device.
+ * @fd: fd of the file to be used as a backing file for the loop device.
+ * @block_size: block size to use; ignored if 0.
+ * @info: struct loop_info64 to configure the loop device with.
+ *
+ * This structure is used with the LOOP_CONFIGURE ioctl, and can be used to
+ * atomically setup and configure all loop device parameters at once.
+ */
+struct xloop_config {
+ __u32 fd;
+ __u32 block_size;
+ struct xloop_info64 info;
+ __u64 __reserved[8];
+};
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/libmsgctl.h b/src/kernel/tests/include/libmsgctl.h
new file mode 100644
index 0000000..e1afeab
--- /dev/null
+++ b/src/kernel/tests/include/libmsgctl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2002
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBMSGCTL_H__
+#define __LIBMSGCTL_H__
+
+#define FAIL 1
+#define PASS 0
+
+struct mbuffer {
+ long type;
+ struct {
+ char len;
+ char pbytes[99];
+ } data;
+};
+
+int doreader(long key, int tid, long type, int child, int nreps);
+int dowriter(long key, int tid, long type, int child, int nreps);
+int fill_buffer(char *buf, char val, int size);
+int verify(char *buf, char val, int size, int child);
+
+#endif /*__LIBMSGCTL_H__ */
diff --git a/src/kernel/tests/include/libnewipc.h b/src/kernel/tests/include/libnewipc.h
new file mode 100644
index 0000000..30288cd
--- /dev/null
+++ b/src/kernel/tests/include/libnewipc.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Xiao Yang <yangx.jy@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+
+/*
+ * common definitions for the IPC system calls.
+ */
+
+#ifndef __LIBNEWIPC_H
+#define __LIBNEWIPC_H 1
+
+#include <sys/types.h>
+
+#define MSG_RD 0400
+#define MSG_WR 0200
+#define MSG_RW (MSG_RD | MSG_WR)
+#define MSGSIZE 1024
+#define MSGTYPE 1
+#define NR_MSGQUEUES 16
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#define SEM_RD 0400
+#define SEM_ALT 0200
+#define SEM_RA (SEM_RD | SEM_ALT)
+#define PSEMS 10
+
+#define SHM_RD 0400
+#define SHM_WR 0200
+#define SHM_RW (SHM_RD | SHM_WR)
+#define SHM_SIZE 2048
+#define INT_SIZE 4
+#define MODE_MASK 0x01FF
+
+key_t getipckey(const char *file, const int lineno);
+#define GETIPCKEY() \
+ getipckey(__FILE__, __LINE__)
+
+int get_used_queues(const char *file, const int lineno);
+#define GET_USED_QUEUES() \
+ get_used_queues(__FILE__, __LINE__)
+
+void *probe_free_addr(const char *file, const int lineno);
+#define PROBE_FREE_ADDR() \
+ probe_free_addr(__FILE__, __LINE__)
+
+#endif /* newlibipc.h */
diff --git a/src/kernel/tests/include/libsigwait.h b/src/kernel/tests/include/libsigwait.h
new file mode 100644
index 0000000..2fca578
--- /dev/null
+++ b/src/kernel/tests/include/libsigwait.h
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef SIGWAIT_H__
+#define SIGWAIT_H__
+
+#include "tst_test.h"
+#include "tst_timer.h"
+#include <signal.h>
+
+/* swi: sigwaitinfo() */
+typedef int (*swi_func) (const sigset_t * set, siginfo_t * info,
+ void * timeout);
+typedef void (*test_func) (swi_func, int, enum tst_ts_type type);
+
+struct sigwait_test_desc {
+ test_func tf;
+ int signo;
+};
+
+void test_empty_set(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_timeout(swi_func sigwaitinfo, int signo, enum tst_ts_type type);
+void test_unmasked_matching(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_unmasked_matching_noinfo(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_masked_matching(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_masked_matching_rt(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_masked_matching_noinfo(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_bad_address(swi_func sigwaitinfo, int signo,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_bad_address2(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void test_bad_address3(swi_func sigwaitinfo, int signo LTP_ATTRIBUTE_UNUSED,
+ enum tst_ts_type type LTP_ATTRIBUTE_UNUSED);
+void sigwait_setup(void);
+#endif /* SIGWAIT_H__ */
diff --git a/src/kernel/tests/include/old/cleanup.c b/src/kernel/tests/include/old/cleanup.c
new file mode 100644
index 0000000..040dff8
--- /dev/null
+++ b/src/kernel/tests/include/old/cleanup.c
@@ -0,0 +1,47 @@
+/*
+ * Default cleanup logic because linux_syscall_numbers.h's need for cleanup
+ * and binutils bugs suck.
+ *
+ * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __CLEANUP_C__
+#define __CLEANUP_C__
+
+/* Did the user define a cleanup function? */
+#ifndef CLEANUP
+#define USING_DUMMY_CLEANUP 1
+#define CLEANUP dummy_cleanup
+#endif
+
+/* A freebie for defining the function prototype. */
+static void CLEANUP(void) __attribute__ ((unused));
+
+#ifdef USING_DUMMY_CLEANUP
+/* The stub function. Wewt.. */
+static void dummy_cleanup(void)
+{
+}
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/old/ltp_cpuid.h b/src/kernel/tests/include/old/ltp_cpuid.h
new file mode 100644
index 0000000..6bd5537
--- /dev/null
+++ b/src/kernel/tests/include/old/ltp_cpuid.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012-2013 The Chromium OS Authors. All rights reserved.
+ *
+ * Licensed under the BSD 3-clause.
+ */
+
+#ifndef __LTP_CPUID_H__
+#define __LTP_CPUID_H__
+
+static inline void cpuid(unsigned int info, unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ unsigned int _eax = info, _ebx, _ecx, _edx;
+ asm volatile(
+# ifdef __i386__
+ "xchg %%ebx, %%esi;" /* save ebx (for PIC) */
+ "cpuid;"
+ "xchg %%esi, %%ebx;" /* restore ebx & pass to caller */
+ : "=S" (_ebx),
+# else
+ "cpuid;"
+ : "=b" (_ebx),
+# endif
+ "+a" (_eax), "=c" (_ecx), "=d" (_edx)
+ : /* inputs: eax is handled above */
+ );
+ if (eax) *eax = _eax;
+ if (ebx) *ebx = _ebx;
+ if (ecx) *ecx = _ecx;
+ if (edx) *edx = _edx;
+#endif
+}
+
+#endif
diff --git a/src/kernel/tests/include/old/ltp_priv.h b/src/kernel/tests/include/old/ltp_priv.h
new file mode 100644
index 0000000..0552457
--- /dev/null
+++ b/src/kernel/tests/include/old/ltp_priv.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LTP_PRIV_H__
+#define __LTP_PRIV_H__
+
+#include <stdarg.h>
+
+/*
+ * This is the default temporary directory used by tst_tmpdir().
+ *
+ * This is used when TMPDIR env variable is not set.
+ */
+#define TEMPDIR "/tmp"
+
+/*
+ * Default filesystem to be used for tests.
+ */
+#define DEFAULT_FS_TYPE "ext2"
+
+/* environment variables for controlling tst_res verbosity */
+#define TOUT_VERBOSE_S "VERBOSE" /* All test cases reported */
+#define TOUT_NOPASS_S "NOPASS" /* No pass test cases are reported */
+#define TOUT_DISCARD_S "DISCARD" /* No output is reported */
+
+#define USC_ITERATION_ENV "USC_ITERATIONS"
+#define USC_LOOP_WALLTIME "USC_LOOP_WALLTIME"
+#define USC_NO_FUNC_CHECK "USC_NO_FUNC_CHECK"
+#define USC_LOOP_DELAY "USC_LOOP_DELAY"
+
+const char *parse_opts(int ac, char **av, const option_t *user_optarr, void
+ (*uhf)(void));
+
+/* Interface for rerouting to new lib calls from tst_res.c */
+extern void *tst_test;
+
+void tst_vbrk_(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va) __attribute__((noreturn));
+
+void tst_brk_(const char *file, const int lineno, int ttype,
+ const char *msg, ...);
+
+void tst_vres_(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va);
+
+void tst_res_(const char *file, const int lineno, int ttype,
+ const char *msg, ...);
+
+
+#define NO_NEWLIB_ASSERT(file, lineno) \
+ if (tst_test) { \
+ tst_brk_(file, lineno, TBROK, \
+ "%s() executed from newlib!", __FUNCTION__); \
+ }
+
+#endif /* __LTP_PRIV_H__ */
diff --git a/src/kernel/tests/include/old/ltp_signal.h b/src/kernel/tests/include/old/ltp_signal.h
new file mode 100644
index 0000000..02ee834
--- /dev/null
+++ b/src/kernel/tests/include/old/ltp_signal.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved.
+ * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Liu Bo <liubo2009@cn.fujitsu.com>
+ * Author: Ngie Cooper <yaneurabeya@gmail.com>
+ *
+ */
+
+#ifndef __LTP_SIGNAL_H
+#define __LTP_SIGNAL_H
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include "config.h"
+
+/*
+ * For all but __mips__:
+ *
+ * _COMPAT_NSIG / _COMPAT_NSIG_BPW == 2.
+ *
+ * For __mips__:
+ *
+ * _COMPAT_NSIG / _COMPAT_NSIG_BPW == 4.
+ *
+ * See asm/compat.h under the kernel source for more details.
+ *
+ * Multiply that by a fudge factor of 4 and you have your SIGSETSIZE.
+ */
+#if defined __mips__
+#define SIGSETSIZE 16
+#else
+#define SIGSETSIZE (_NSIG / 8)
+#endif
+
+#endif
diff --git a/src/kernel/tests/include/old/old_checkpoint.h b/src/kernel/tests/include/old/old_checkpoint.h
new file mode 100644
index 0000000..c8ffc92
--- /dev/null
+++ b/src/kernel/tests/include/old/old_checkpoint.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /*
+
+ Checkpoint - easy to use parent-child synchronization.
+
+ Checkpoint is based on futexes (man futex). The library allocates a page of
+ shared memory for futexes and the id is an offset to it which gives the user
+ up to page_size/sizeof(uint32_t) checkpoint pairs. Up to INT_MAX processes
+ can sleep on single id and can be woken up by single wake.
+
+ */
+
+#ifndef OLD_CHECKPOINT__
+#define OLD_CHECKPOINT__
+
+#include "test.h"
+#include "tst_checkpoint_fn.h"
+
+/*
+ * Checkpoint initializaton, must be done first.
+ *
+ * NOTE: tst_tmpdir() must be called beforehand.
+ */
+#define TST_CHECKPOINT_INIT(cleanup_fn) \
+ tst_checkpoint_init(__FILE__, __LINE__, cleanup_fn)
+
+#define TST_SAFE_CHECKPOINT_WAIT(cleanup_fn, id) \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, 0);
+
+#define TST_SAFE_CHECKPOINT_WAIT2(cleanup_fn, id, msec_timeout) \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, msec_timeout);
+
+#define TST_SAFE_CHECKPOINT_WAKE(cleanup_fn, id) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, 1);
+
+#define TST_SAFE_CHECKPOINT_WAKE2(cleanup_fn, id, nr_wake) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, nr_wake);
+
+#define TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup_fn, id) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, cleanup_fn, id, 1); \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, cleanup_fn, id, 0);
+
+#endif /* OLD_CHECKPOINT__ */
diff --git a/src/kernel/tests/include/old/old_device.h b/src/kernel/tests/include/old/old_device.h
new file mode 100644
index 0000000..a6e9fea
--- /dev/null
+++ b/src/kernel/tests/include/old/old_device.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OLD_DEVICE_H__
+#define OLD_DEVICE_H__
+
+/*
+ * Returns filesystem type to be used for the testing. Unless your test is
+ * designed for specific filesystem you should use this function to the tested
+ * filesystem.
+ *
+ * If TST_DEV_FS_TYPE is set the function returns it's content,
+ * otherwise default fs type hardcoded in the library is returned.
+ */
+const char *tst_dev_fs_type(void);
+
+/*
+ * Acquires test device.
+ *
+ * Can be used only once, i.e. you cannot get two different devices.
+ *
+ * Looks for LTP_DEV env variable first (which may be passed by the test
+ * driver or by a user) and returns just it's value if found.
+ *
+ * Otherwise creates a temp file and loop device.
+ *
+ * Note that you have to call tst_tmpdir() beforehand.
+ *
+ * Returns path to the device or NULL if it cannot be created.
+ * Call tst_release_device() when you're done.
+ */
+const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size);
+
+const char *tst_acquire_device__(unsigned int size);
+
+static inline const char *tst_acquire_device(void (cleanup_fn)(void))
+{
+ return tst_acquire_device_(cleanup_fn, 0);
+}
+
+/*
+ * Acquire a loop device with specified temp filename. This function allows
+ * you to acquire multiple devices at the same time. LTP_DEV is ignored.
+ * If you call this function directly, use tst_detach_device() to release
+ * the devices. tst_release_device() will not work correctly.
+ *
+ * The return value points to a static buffer and additional calls of
+ * tst_acquire_loop_device() or tst_acquire_device() will overwrite it.
+ */
+const char *tst_acquire_loop_device(unsigned int size, const char *filename);
+
+/*
+ * @dev: device path returned by the tst_acquire_device()
+ */
+int tst_release_device(const char *dev);
+
+/*
+ * Cleanup function for tst_acquire_loop_device(). If you have acquired
+ * a device using tst_acquire_device(), use tst_release_device() instead.
+ * @dev: device path returned by the tst_acquire_loop_device()
+ */
+int tst_detach_device(const char *dev);
+
+/*
+ * Just like umount() but retries several times on failure.
+ * @path: Path to umount
+ */
+int tst_umount(const char *path);
+
+#endif /* OLD_DEVICE_H__ */
diff --git a/src/kernel/tests/include/old/old_module.h b/src/kernel/tests/include/old/old_module.h
new file mode 100644
index 0000000..c50efec
--- /dev/null
+++ b/src/kernel/tests/include/old/old_module.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ * These functions help to load and unload kernel modules in the tests.
+ *
+ * tst_module_load function already includes tst_module_exists function,
+ * which is checking the following possible module's locations:
+ *
+ * 1. Current working directory
+ *
+ * 2. LTP installation path (using env LTPROOT, which is usually /opt/ltp)
+ *
+ * 3. If tmp directory created, it'll look at the test start working directory
+ *
+ */
+
+#ifndef TST_MODULE
+#define TST_MODULE
+
+/*
+ * Check module existence.
+ *
+ * @mod_name: module's file name.
+ * @mod_path: if it is not NULL, then tst_module_exists places the found
+ * module's path into the location pointed to by *mod_path. It must be freed
+ * with free() when it is no longer needed.
+ *
+ * In case of failure, test'll call cleanup_fn and exit with TCONF return value.
+ */
+void tst_module_exist(void (cleanup_fn)(void), const char *mod_name,
+ char **mod_path);
+
+/*
+ * Load a module using insmod program.
+ *
+ * @mod_name: module's file name.
+ * @argv: an array of pointers to null-terminated strings that represent the
+ * additional parameters to the module. The array of pointers must be
+ * terminated by a NULL pointer. If argv points to NULL, it will be ignored.
+ *
+ * In case of insmod failure, test will call cleanup_fn and exit with TBROK
+ * return value.
+ */
+void tst_module_load(void (cleanup_fn)(void),
+ const char *mod_name, char *const argv[]);
+
+/*
+ * Unload a module using rmmod program. In case of failure, test will call
+ * cleanup_fn and exit with TBROK return value.
+ *
+ * @mod_name: can be module name or module's file name.
+ */
+void tst_module_unload(void (cleanup_fn)(void), const char *mod_name);
+
+#endif /* TST_MODULE */
diff --git a/src/kernel/tests/include/old/old_resource.h b/src/kernel/tests/include/old/old_resource.h
new file mode 100644
index 0000000..46767f3
--- /dev/null
+++ b/src/kernel/tests/include/old/old_resource.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+ /*
+
+ Small helper for preparing files the test needs to copy before the testing.
+
+ We need to support two scenarios.
+
+ 1. Test is executed in local directory and this is also the place
+ we should look for files
+
+
+ 2. Test is executed after LTP has been installed, in this case we
+ look for env LTPROOT (usually /opt/ltp/)
+
+ */
+
+#ifndef TST_RESOURCE
+#define TST_RESOURCE
+
+const char *tst_dataroot(void);
+
+/*
+ * Copy a file to the CWD. The destination is apended to CWD.
+ */
+#define TST_RESOURCE_COPY(cleanup_fn, filename, dest) \
+ tst_resource_copy(__FILE__, __LINE__, (cleanup_fn), \
+ (filename), (dest))
+
+void tst_resource_copy(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *filename, const char *dest);
+
+#endif /* TST_RESOURCE */
diff --git a/src/kernel/tests/include/old/old_safe_file_ops.h b/src/kernel/tests/include/old/old_safe_file_ops.h
new file mode 100644
index 0000000..d6e2d29
--- /dev/null
+++ b/src/kernel/tests/include/old/old_safe_file_ops.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /*
+
+ This code helps with file reading/writing files providing scanf/printf like
+ interface that opens and closes the file automatically.
+
+ This kind of interface is especially useful for reading/writing values
+ from/to pseudo filesystems like procfs or sysfs.
+
+ */
+
+#ifndef SAFE_FILE_OPS
+#define SAFE_FILE_OPS
+
+#include "safe_file_ops_fn.h"
+
+#define FILE_SCANF(path, fmt, ...) \
+ file_scanf(__FILE__, __LINE__, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_FILE_SCANF(cleanup_fn, path, fmt, ...) \
+ safe_file_scanf(__FILE__, __LINE__, (cleanup_fn), \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define FILE_LINES_SCANF(cleanup_fn, path, fmt, ...) \
+ file_lines_scanf(__FILE__, __LINE__, (cleanup_fn), 0, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_FILE_LINES_SCANF(cleanup_fn, path, fmt, ...) \
+ file_lines_scanf(__FILE__, __LINE__, (cleanup_fn), 1, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define FILE_PRINTF(path, fmt, ...) \
+ file_printf(__FILE__, __LINE__, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_FILE_PRINTF(cleanup_fn, path, fmt, ...) \
+ safe_file_printf(__FILE__, __LINE__, (cleanup_fn), \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_CP(cleanup_fn, src, dst) \
+ safe_cp(__FILE__, __LINE__, (cleanup_fn), (src), (dst))
+
+#define SAFE_TOUCH(cleanup_fn, pathname, mode, times) \
+ safe_touch(__FILE__, __LINE__, (cleanup_fn), \
+ (pathname), (mode), (times))
+
+#endif /* SAFE_FILE_OPS */
diff --git a/src/kernel/tests/include/old/old_safe_net.h b/src/kernel/tests/include/old/old_safe_net.h
new file mode 100644
index 0000000..639094a
--- /dev/null
+++ b/src/kernel/tests/include/old/old_safe_net.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015 Fujitsu Ltd.
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OLD_SAFE_NET_H__
+#define OLD_SAFE_NET_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+
+#include "safe_net_fn.h"
+
+#define SAFE_SOCKET(cleanup_fn, domain, type, protocol) \
+ safe_socket(__FILE__, __LINE__, (cleanup_fn), domain, type, protocol)
+
+#define SAFE_BIND(cleanup_fn, socket, address, address_len) \
+ safe_bind(__FILE__, __LINE__, (cleanup_fn), socket, address, \
+ address_len)
+
+#define SAFE_LISTEN(cleanup_fn, socket, backlog) \
+ safe_listen(__FILE__, __LINE__, (cleanup_fn), socket, backlog)
+
+#define SAFE_CONNECT(cleanup_fn, sockfd, addr, addrlen) \
+ safe_connect(__FILE__, __LINE__, (cleanup_fn), sockfd, addr, addrlen)
+
+#define SAFE_GETSOCKNAME(cleanup_fn, sockfd, addr, addrlen) \
+ safe_getsockname(__FILE__, __LINE__, (cleanup_fn), sockfd, addr, \
+ addrlen)
+
+#define TST_GET_UNUSED_PORT(cleanup_fn, family, type) \
+ tst_get_unused_port(__FILE__, __LINE__, (cleanup_fn), family, type)
+
+#endif /* OLD_SAFE_NET_H__ */
diff --git a/src/kernel/tests/include/old/old_safe_stdio.h b/src/kernel/tests/include/old/old_safe_stdio.h
new file mode 100644
index 0000000..3508b24
--- /dev/null
+++ b/src/kernel/tests/include/old/old_safe_stdio.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OLD_SAFE_STDIO_H__
+#define OLD_SAFE_STDIO_H__
+
+#include <stdio.h>
+
+#include "safe_stdio_fn.h"
+
+#define SAFE_FOPEN(cleanup_fn, path, mode) \
+ safe_fopen(__FILE__, __LINE__, cleanup_fn, path, mode)
+
+#define SAFE_FCLOSE(cleanup_fn, f) \
+ safe_fclose(__FILE__, __LINE__, cleanup_fn, f)
+
+#define SAFE_ASPRINTF(cleanup_fn, strp, fmt, ...) \
+ safe_asprintf(__FILE__, __LINE__, cleanup_fn, strp, fmt, __VA_ARGS__)
+
+#define SAFE_POPEN(cleanup_fn, command, type) \
+ safe_popen(__FILE__, __LINE__, cleanup_fn, command, type)
+
+#endif /* OLD_SAFE_STDIO_H__ */
diff --git a/src/kernel/tests/include/old/old_tmpdir.h b/src/kernel/tests/include/old/old_tmpdir.h
new file mode 100644
index 0000000..9c61172
--- /dev/null
+++ b/src/kernel/tests/include/old/old_tmpdir.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OLD_TMPDIR_H__
+#define OLD_TMPDIR_H__
+
+/*
+ * Create a unique temporary directory and chdir() to it. It expects the caller
+ * to have defined/initialized the TCID/TST_TOTAL global variables.
+ * The TESTDIR global variable will be set to the directory that gets used
+ * as the testing directory.
+ *
+ * NOTE: This function must be called BEFORE any activity that would require
+ * CLEANUP. If tst_tmpdir() fails, it cleans up afer itself and calls
+ * tst_exit() (i.e. does not return).
+ */
+void tst_tmpdir(void);
+
+/*
+ * Recursively remove the temporary directory created by tst_tmpdir().
+ * This function is intended ONLY as a companion to tst_tmpdir().
+ */
+void tst_rmdir(void);
+
+/* tst_get_tmpdir()
+ *
+ * Return a copy of the test temp directory as seen by LTP. This is for
+ * path-oriented tests like chroot, etc, that may munge the path a bit.
+ *
+ * FREE VARIABLE AFTER USE IF IT IS REUSED!
+ */
+char *tst_get_tmpdir(void);
+
+/*
+ * Returns 1 if temp directory was created.
+ */
+int tst_tmpdir_created(void);
+
+/* declared in tst_tmpdir.c */
+const char *tst_get_startwd(void);
+
+#endif /* OLD_TMPDIR_H__ */
diff --git a/src/kernel/tests/include/old/random_range.h b/src/kernel/tests/include/old/random_range.h
new file mode 100644
index 0000000..22b3f93
--- /dev/null
+++ b/src/kernel/tests/include/old/random_range.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _RANDOM_RANGE_H_
+#define _RANDOM_RANGE_H_
+
+int parse_ranges ( char *, int, int, int, int (*)(), char **, char ** );
+int range_min ( char *, int );
+int range_max ( char *, int );
+int range_mult ( char *, int );
+long random_range ( int, int, int, char ** );
+long random_rangel ( long, long, long, char ** );
+long long random_rangell ( long long, long long, long long, char ** );
+void random_range_seed( long );
+long random_bit ( long );
+
+#endif
diff --git a/src/kernel/tests/include/old/safe_macros.h b/src/kernel/tests/include/old/safe_macros.h
new file mode 100644
index 0000000..e778d30
--- /dev/null
+++ b/src/kernel/tests/include/old/safe_macros.h
@@ -0,0 +1,340 @@
+/*
+ * Safe macros for commonly used syscalls to reduce code duplication in LTP
+ * testcases, and to ensure all errors are caught in said testcases as
+ * gracefully as possible.
+ *
+ * Also satiates some versions of gcc/glibc when the warn_unused_result
+ * attribute is applied to the function call.
+ *
+ * Licensed under the GPLv2.
+ */
+
+#ifndef __TEST_H__
+#error "you must include test.h before this file"
+#else
+
+#ifndef __SAFE_MACROS_H__
+#define __SAFE_MACROS_H__
+
+#include "safe_macros_fn.h"
+#include "old_safe_stdio.h"
+#include "old_safe_net.h"
+
+#define SAFE_BASENAME(cleanup_fn, path) \
+ safe_basename(__FILE__, __LINE__, (cleanup_fn), (path))
+
+#define SAFE_CHDIR(cleanup_fn, path) \
+ safe_chdir(__FILE__, __LINE__, (cleanup_fn), (path))
+
+#define SAFE_CLOSE(cleanup_fn, fd) ({ \
+ int ret = safe_close(__FILE__, __LINE__, (cleanup_fn), (fd)); \
+ fd = -1; \
+ ret; \
+ })
+
+#define SAFE_CREAT(cleanup_fn, pathname, mode) \
+ safe_creat(__FILE__, __LINE__, cleanup_fn, (pathname), (mode))
+
+#define SAFE_DIRNAME(cleanup_fn, path) \
+ safe_dirname(__FILE__, __LINE__, (cleanup_fn), (path))
+
+#define SAFE_GETCWD(cleanup_fn, buf, size) \
+ safe_getcwd(__FILE__, __LINE__, (cleanup_fn), (buf), (size))
+
+#define SAFE_GETPWNAM(cleanup_fn, name) \
+ safe_getpwnam(__FILE__, __LINE__, cleanup_fn, (name))
+
+#define SAFE_GETRUSAGE(cleanup_fn, who, usage) \
+ safe_getrusage(__FILE__, __LINE__, (cleanup_fn), (who), (usage))
+
+#define SAFE_MALLOC(cleanup_fn, size) \
+ safe_malloc(__FILE__, __LINE__, (cleanup_fn), (size))
+
+#define SAFE_MKDIR(cleanup_fn, pathname, mode) \
+ safe_mkdir(__FILE__, __LINE__, (cleanup_fn), (pathname), (mode))
+
+#define SAFE_RMDIR(cleanup_fn, pathname) \
+ safe_rmdir(__FILE__, __LINE__, (cleanup_fn), (pathname))
+
+#define SAFE_MUNMAP(cleanup_fn, addr, length) \
+ safe_munmap(__FILE__, __LINE__, (cleanup_fn), (addr), (length))
+
+#define SAFE_OPEN(cleanup_fn, pathname, oflags, ...) \
+ safe_open(__FILE__, __LINE__, (cleanup_fn), (pathname), (oflags), \
+ ##__VA_ARGS__)
+
+#define SAFE_PIPE(cleanup_fn, fildes) \
+ safe_pipe(__FILE__, __LINE__, cleanup_fn, (fildes))
+
+#define SAFE_READ(cleanup_fn, len_strict, fildes, buf, nbyte) \
+ safe_read(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
+ (buf), (nbyte))
+
+#define SAFE_SETEGID(cleanup_fn, egid) \
+ safe_setegid(__FILE__, __LINE__, cleanup_fn, (egid))
+
+#define SAFE_SETEUID(cleanup_fn, euid) \
+ safe_seteuid(__FILE__, __LINE__, cleanup_fn, (euid))
+
+#define SAFE_SETGID(cleanup_fn, gid) \
+ safe_setgid(__FILE__, __LINE__, cleanup_fn, (gid))
+
+#define SAFE_SETUID(cleanup_fn, uid) \
+ safe_setuid(__FILE__, __LINE__, cleanup_fn, (uid))
+
+#define SAFE_GETRESUID(cleanup_fn, ruid, euid, suid) \
+ safe_getresuid(__FILE__, __LINE__, cleanup_fn, (ruid), (euid), (suid))
+
+#define SAFE_GETRESGID(cleanup_fn, rgid, egid, sgid) \
+ safe_getresgid(__FILE__, __LINE__, cleanup_fn, (rgid), (egid), (sgid))
+
+#define SAFE_UNLINK(cleanup_fn, pathname) \
+ safe_unlink(__FILE__, __LINE__, cleanup_fn, (pathname))
+
+#define SAFE_LINK(cleanup_fn, oldpath, newpath) \
+ safe_link(__FILE__, __LINE__, cleanup_fn, (oldpath), (newpath))
+
+#define SAFE_LINKAT(cleanup_fn, olddirfd, oldpath, newdirfd, newpath, flags) \
+ safe_linkat(__FILE__, __LINE__, cleanup_fn, (olddirfd), (oldpath), \
+ (newdirfd), (newpath), (flags))
+
+#define SAFE_READLINK(cleanup_fn, path, buf, bufsize) \
+ safe_readlink(__FILE__, __LINE__, cleanup_fn, (path), (buf), (bufsize))
+
+#define SAFE_SYMLINK(cleanup_fn, oldpath, newpath) \
+ safe_symlink(__FILE__, __LINE__, cleanup_fn, (oldpath), (newpath))
+
+#define SAFE_WRITE(cleanup_fn, len_strict, fildes, buf, nbyte) \
+ safe_write(__FILE__, __LINE__, cleanup_fn, (len_strict), (fildes), \
+ (buf), (nbyte))
+
+#define SAFE_STRTOL(cleanup_fn, str, min, max) \
+ safe_strtol(__FILE__, __LINE__, cleanup_fn, (str), (min), (max))
+
+#define SAFE_STRTOUL(cleanup_fn, str, min, max) \
+ safe_strtoul(__FILE__, __LINE__, cleanup_fn, (str), (min), (max))
+
+#define SAFE_SYSCONF(cleanup_fn, name) \
+ safe_sysconf(__FILE__, __LINE__, cleanup_fn, name)
+
+#define SAFE_CHMOD(cleanup_fn, path, mode) \
+ safe_chmod(__FILE__, __LINE__, (cleanup_fn), (path), (mode))
+
+#define SAFE_FCHMOD(cleanup_fn, fd, mode) \
+ safe_fchmod(__FILE__, __LINE__, (cleanup_fn), (fd), (mode))
+
+#define SAFE_CHOWN(cleanup_fn, path, owner, group) \
+ safe_chown(__FILE__, __LINE__, (cleanup_fn), (path), (owner), (group))
+
+#define SAFE_FCHOWN(cleanup_fn, fd, owner, group) \
+ safe_fchown(__FILE__, __LINE__, (cleanup_fn), (fd), (owner), (group))
+
+#define SAFE_WAIT(cleanup_fn, status) \
+ safe_wait(__FILE__, __LINE__, (cleanup_fn), (status))
+
+#define SAFE_WAITPID(cleanup_fn, pid, status, opts) \
+ safe_waitpid(__FILE__, __LINE__, (cleanup_fn), (pid), (status), (opts))
+
+#define SAFE_KILL(cleanup_fn, pid, sig) \
+ safe_kill(__FILE__, __LINE__, (cleanup_fn), (pid), (sig))
+
+#define SAFE_MEMALIGN(cleanup_fn, alignment, size) \
+ safe_memalign(__FILE__, __LINE__, (cleanup_fn), (alignment), (size))
+
+#define SAFE_MKFIFO(cleanup_fn, pathname, mode) \
+ safe_mkfifo(__FILE__, __LINE__, (cleanup_fn), (pathname), (mode))
+
+#define SAFE_RENAME(cleanup_fn, oldpath, newpath) \
+ safe_rename(__FILE__, __LINE__, (cleanup_fn), (oldpath), (newpath))
+
+#define SAFE_MOUNT(cleanup_fn, source, target, filesystemtype, \
+ mountflags, data) \
+ safe_mount(__FILE__, __LINE__, (cleanup_fn), (source), (target), \
+ (filesystemtype), (mountflags), (data))
+
+#define SAFE_UMOUNT(cleanup_fn, target) \
+ safe_umount(__FILE__, __LINE__, (cleanup_fn), (target))
+
+/*
+ * following functions are inline because the behaviour may depend on
+ * -D_FILE_OFFSET_BITS=64 -DOFF_T=__off64_t compile flags
+ */
+
+static inline void *safe_mmap(const char *file, const int lineno,
+ void (*cleanup_fn)(void), void *addr, size_t length,
+ int prot, int flags, int fd, off_t offset)
+{
+ void *rval;
+
+ rval = mmap(addr, length, prot, flags, fd, offset);
+ if (rval == MAP_FAILED) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: mmap(%p,%zu,%d,%d,%d,%ld) failed",
+ file, lineno, addr, length, prot, flags, fd,
+ (long) offset);
+ }
+
+ return rval;
+}
+#define SAFE_MMAP(cleanup_fn, addr, length, prot, flags, fd, offset) \
+ safe_mmap(__FILE__, __LINE__, (cleanup_fn), (addr), (length), (prot), \
+ (flags), (fd), (offset))
+
+static inline int safe_ftruncate(const char *file, const int lineno,
+ void (cleanup_fn) (void), int fd, off_t length)
+{
+ int rval;
+
+ rval = ftruncate(fd, length);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: ftruncate(%d,%ld) failed",
+ file, lineno, fd, (long)length);
+ }
+
+ return rval;
+}
+#define SAFE_FTRUNCATE(cleanup_fn, fd, length) \
+ safe_ftruncate(__FILE__, __LINE__, cleanup_fn, (fd), (length))
+
+static inline int safe_truncate(const char *file, const int lineno,
+ void (cleanup_fn) (void), const char *path, off_t length)
+{
+ int rval;
+
+ rval = truncate(path, length);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: truncate(%s,%ld) failed",
+ file, lineno, path, (long)length);
+ }
+
+ return rval;
+}
+#define SAFE_TRUNCATE(cleanup_fn, path, length) \
+ safe_truncate(__FILE__, __LINE__, cleanup_fn, (path), (length))
+
+static inline int safe_stat(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *path, struct stat *buf)
+{
+ int rval;
+
+ rval = stat(path, buf);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: stat(%s,%p) failed", file, lineno, path, buf);
+ }
+
+ return rval;
+}
+#define SAFE_STAT(cleanup_fn, path, buf) \
+ safe_stat(__FILE__, __LINE__, (cleanup_fn), (path), (buf))
+
+static inline int safe_fstat(const char *file, const int lineno,
+ void (cleanup_fn)(void), int fd, struct stat *buf)
+{
+ int rval;
+
+ rval = fstat(fd, buf);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: fstat(%d,%p) failed", file, lineno, fd, buf);
+ }
+
+ return rval;
+}
+#define SAFE_FSTAT(cleanup_fn, fd, buf) \
+ safe_fstat(__FILE__, __LINE__, (cleanup_fn), (fd), (buf))
+
+static inline int safe_lstat(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *path, struct stat *buf)
+{
+ int rval;
+
+ rval = lstat(path, buf);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: lstat(%s,%p) failed", file, lineno, path, buf);
+ }
+
+ return rval;
+}
+#define SAFE_LSTAT(cleanup_fn, path, buf) \
+ safe_lstat(__FILE__, __LINE__, (cleanup_fn), (path), (buf))
+
+static inline off_t safe_lseek(const char *file, const int lineno,
+ void (cleanup_fn)(void), int fd, off_t offset, int whence)
+{
+ off_t rval;
+
+ rval = lseek(fd, offset, whence);
+
+ if (rval == (off_t) -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: lseek(%d,%ld,%d) failed",
+ file, lineno, fd, (long)offset, whence);
+ }
+
+ return rval;
+}
+#define SAFE_LSEEK(cleanup_fn, fd, offset, whence) \
+ safe_lseek(__FILE__, __LINE__, cleanup_fn, (fd), (offset), (whence))
+
+static inline int safe_getrlimit(const char *file, const int lineno,
+ void (cleanup_fn)(void), int resource, struct rlimit *rlim)
+{
+ int rval;
+
+ rval = getrlimit(resource, rlim);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getrlimit(%d,%p) failed",
+ file, lineno, resource, rlim);
+ }
+
+ return rval;
+}
+#define SAFE_GETRLIMIT(cleanup_fn, resource, rlim) \
+ safe_getrlimit(__FILE__, __LINE__, (cleanup_fn), (resource), (rlim))
+
+static inline int safe_setrlimit(const char *file, const int lineno,
+ void (cleanup_fn)(void), int resource, const struct rlimit *rlim)
+{
+ int rval;
+
+ rval = setrlimit(resource, rlim);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: setrlimit(%d,%p) failed",
+ file, lineno, resource, rlim);
+ }
+
+ return rval;
+}
+#define SAFE_SETRLIMIT(cleanup_fn, resource, rlim) \
+ safe_setrlimit(__FILE__, __LINE__, (cleanup_fn), (resource), (rlim))
+
+#define SAFE_OPENDIR(cleanup_fn, name) \
+ safe_opendir(__FILE__, __LINE__, (cleanup_fn), (name))
+
+#define SAFE_CLOSEDIR(cleanup_fn, dirp) \
+ safe_closedir(__FILE__, __LINE__, (cleanup_fn), (dirp))
+
+#define SAFE_READDIR(cleanup_fn, dirp) \
+ safe_readdir(__FILE__, __LINE__, (cleanup_fn), (dirp))
+
+
+#define SAFE_IOCTL(cleanup_fn, fd, request, ...) \
+ ({int ret = ioctl(fd, request, __VA_ARGS__); \
+ if (ret < 0) \
+ tst_brkm(TBROK | TERRNO, cleanup_fn, \
+ "ioctl(%i,%s,...) failed", fd, #request); \
+ ret;})
+
+#endif /* __SAFE_MACROS_H__ */
+#endif /* __TEST_H__ */
diff --git a/src/kernel/tests/include/old/test.h b/src/kernel/tests/include/old/test.h
new file mode 100644
index 0000000..604254e
--- /dev/null
+++ b/src/kernel/tests/include/old/test.h
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2009-2013 Cyril Hrubis chrubis@suse.cz
+ */
+
+#ifndef __TEST_H__
+#define __TEST_H__
+
+#ifdef TST_TEST_H__
+# error Newlib tst_test.h already included
+#endif /* TST_TEST_H__ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "usctest.h"
+
+#include "tst_common.h"
+#include "old_safe_file_ops.h"
+#include "old_checkpoint.h"
+#include "tst_process_state.h"
+#include "old_resource.h"
+#include "tst_res_flags.h"
+#include "tst_kvercmp.h"
+#include "tst_fs.h"
+#include "tst_pid.h"
+#include "tst_cmd.h"
+#include "tst_cpu.h"
+#include "tst_clone.h"
+#include "old_device.h"
+#include "old_tmpdir.h"
+#include "tst_minmax.h"
+#include "tst_get_bad_addr.h"
+#include "tst_path_has_mnt_flags.h"
+
+/*
+ * Ensure that NUMSIGS is defined.
+ * It should be defined in signal.h or sys/signal.h on
+ * UNICOS/mk and IRIX systems. On UNICOS systems,
+ * it is not defined, thus it is being set to UNICOS's NSIG.
+ * Note: IRIX's NSIG (signals are 1-(NSIG-1))
+ * is not same meaning as UNICOS/UMK's NSIG (signals 1-NSIG)
+ */
+#ifndef NUMSIGS
+#define NUMSIGS NSIG
+#endif
+
+
+/* defines for unexpected signal setup routine (set_usig.c) */
+#define FORK 1 /* SIGCHLD is to be ignored */
+#define NOFORK 0 /* SIGCHLD is to be caught */
+#define DEF_HANDLER SIG_ERR /* tells set_usig() to use default signal handler */
+
+/*
+ * The following defines are used to control tst_res and t_result reporting.
+ */
+
+#define TOUTPUT "TOUTPUT" /* The name of the environment variable */
+ /* that can be set to one of the following */
+ /* strings to control tst_res output */
+ /* If not set, TOUT_VERBOSE_S is assumed */
+
+/*
+ * fork() can't be used on uClinux systems, so use FORK_OR_VFORK instead,
+ * which will run vfork() on uClinux.
+ * mmap() doesn't support MAP_PRIVATE on uClinux systems, so use
+ * MAP_PRIVATE_EXCEPT_UCLINUX instead, which will skip the option on uClinux.
+ * If MAP_PRIVATE really is required, the test can not be run on uClinux.
+ */
+#ifdef UCLINUX
+# define FORK_OR_VFORK tst_vfork
+# define MAP_PRIVATE_EXCEPT_UCLINUX 0
+/* tst_old_flush() + vfork() */
+pid_t tst_vfork(void);
+#else
+# define FORK_OR_VFORK tst_fork
+# define MAP_PRIVATE_EXCEPT_UCLINUX MAP_PRIVATE
+#endif
+
+/*
+ * Macro to use for making functions called only once in
+ * multi-threaded tests such as init or cleanup function.
+ * The first call to @name_fn function by any thread shall
+ * call the @exec_fn. Subsequent calls shall not call @exec_fn.
+ * *_fn functions must not take any arguments.
+ */
+#define TST_DECLARE_ONCE_FN(name_fn, exec_fn) \
+ void name_fn(void) \
+ { \
+ static pthread_once_t ltp_once = PTHREAD_ONCE_INIT; \
+ pthread_once(&ltp_once, exec_fn); \
+ }
+
+/*
+ * lib/forker.c
+ */
+extern int Forker_pids[];
+extern int Forker_npids;
+
+typedef struct {
+ char *option; /* Valid option string (one option only) like "a:" */
+ int *flag; /* Pointer to location to set true if option given */
+ char **arg; /* Pointer to location to place argument, if needed */
+} option_t;
+
+/* lib/tst_parse_opts.c */
+void tst_parse_opts(int argc, char *argv[], const option_t *user_optarg,
+ void (*user_help)(void));
+
+/* lib/tst_res.c */
+const char *strttype(int ttype);
+
+void tst_resm_(const char *file, const int lineno, int ttype,
+ const char *arg_fmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+#define tst_resm(ttype, arg_fmt, ...) \
+ tst_resm_(__FILE__, __LINE__, (ttype), \
+ (arg_fmt), ##__VA_ARGS__)
+
+void tst_resm_hexd_(const char *file, const int lineno, int ttype,
+ const void *buf, size_t size, const char *arg_fmt, ...)
+ __attribute__ ((format (printf, 6, 7)));
+#define tst_resm_hexd(ttype, buf, size, arg_fmt, ...) \
+ tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \
+ (arg_fmt), ##__VA_ARGS__)
+
+void tst_brkm_(const char *file, const int lineno, int ttype,
+ void (*func)(void), const char *arg_fmt, ...)
+ __attribute__ ((format (printf, 5, 6))) LTP_ATTRIBUTE_NORETURN;
+
+#ifdef LTPLIB
+# include "ltp_priv.h"
+# define tst_brkm(flags, cleanup, fmt, ...) do { \
+ if (tst_test) \
+ tst_brk_(__FILE__, __LINE__, flags, fmt, ##__VA_ARGS__); \
+ else \
+ tst_brkm_(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \
+ } while (0)
+#else
+# define tst_brkm(flags, cleanup, fmt, ...) do { \
+ tst_brkm_(__FILE__, __LINE__, flags, cleanup, fmt, ##__VA_ARGS__); \
+ } while (0)
+#endif
+
+void tst_require_root(void);
+void tst_exit(void) LTP_ATTRIBUTE_NORETURN;
+void tst_old_flush(void);
+
+/*
+ * tst_old_flush() + fork
+ * NOTE: tst_fork() will reset T_exitval to 0 for child process.
+ */
+pid_t tst_fork(void);
+
+/* lib/tst_res.c */
+/*
+ * In case we need do real test work in child process parent process can use
+ * tst_record_childstatus() to make child process's test results propagated to
+ * parent process correctly.
+ *
+ * The child can use tst_resm(), tst_brkm() followed by the tst_exit() or
+ * plain old exit() (with TPASS, TFAIL and TBROK).
+ *
+ * WARNING: Be wary that the child cleanup function passed to tst_brkm()
+ * must clean only resources the child has allocated. E.g. the
+ * child cleanup is different function from the parent cleanup.
+ */
+void tst_record_childstatus(void (*cleanup)(void), pid_t child);
+
+extern int tst_count;
+
+/* lib/tst_sig.c */
+void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)());
+
+/* lib/self_exec.c */
+void maybe_run_child(void (*child)(), const char *fmt, ...);
+int self_exec(const char *argv0, const char *fmt, ...);
+
+/* lib/tst_mkfs.c
+ *
+ * @dev: path to a device
+ * @fs_type: filesystem type
+ * @fs_opts: NULL or NULL terminated array of mkfs options
+ * @extra_opt: extra mkfs option which is passed after the device name
+ */
+#define tst_mkfs(cleanup, dev, fs_type, fs_opts, extra_opts) \
+ tst_mkfs_(__FILE__, __LINE__, cleanup, dev, fs_type, \
+ fs_opts, extra_opts)
+void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *dev, const char *fs_type,
+ const char *const fs_opts[], const char *const extra_opts[]);
+
+/* lib/tst_res.c
+ * tst_strsig converts signal's value to corresponding string.
+ * tst_strerrno converts errno to corresponding string.
+ */
+const char *tst_strsig(int sig);
+const char *tst_strerrno(int err);
+
+#ifdef TST_USE_COMPAT16_SYSCALL
+#define TCID_BIT_SUFFIX "_16"
+#elif TST_USE_NEWER64_SYSCALL
+#define TCID_BIT_SUFFIX "_64"
+#else
+#define TCID_BIT_SUFFIX ""
+#endif
+#define TCID_DEFINE(ID) char *TCID = (#ID TCID_BIT_SUFFIX)
+
+#endif /* __TEST_H__ */
diff --git a/src/kernel/tests/include/old/tlibio.h b/src/kernel/tests/include/old/tlibio.h
new file mode 100644
index 0000000..0fe9ce9
--- /dev/null
+++ b/src/kernel/tests/include/old/tlibio.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+#define LIO_IO_SYNC 00001 /* read/write */
+#define LIO_IO_ASYNC 00002 /* reada/writea/aio_write/aio_read */
+#define LIO_IO_SLISTIO 00004 /* single stride sync listio */
+#define LIO_IO_ALISTIO 00010 /* single stride async listio */
+#define LIO_IO_SYNCV 00020 /* single-buffer readv/writev */
+#define LIO_IO_SYNCP 00040 /* pread/pwrite */
+
+#ifdef sgi
+#define LIO_IO_ATYPES 00077 /* all io types */
+#define LIO_IO_TYPES 00061 /* all io types, non-async */
+#endif /* sgi */
+#if defined(__linux__) && !defined(__UCLIBC__)
+#define LIO_IO_TYPES 00061 /* all io types */
+#define LIO_IO_ATYPES 00077 /* all io types */
+#endif
+#if defined(__sun) || defined(__hpux) || defined(_AIX) || defined(__UCLIBC__)
+#define LIO_IO_TYPES 00021 /* all io types except pread/pwrite */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_IO_TYPES 00017 /* all io types */
+#endif /* CRAY */
+
+#ifndef LIO_IO_ATYPES
+#define LIO_IO_ATYPES LIO_IO_TYPES
+#endif
+
+#define LIO_WAIT_NONE 00010000 /* return asap -- use with care */
+#define LIO_WAIT_ACTIVE 00020000 /* spin looking at iosw fields, or EINPROGRESS */
+#define LIO_WAIT_RECALL 00040000 /* call recall(2)/aio_suspend(3) */
+#define LIO_WAIT_SIGPAUSE 00100000 /* call pause */
+#define LIO_WAIT_SIGACTIVE 00200000 /* spin waiting for signal */
+#if defined(sgi) || defined(__linux__)
+#define LIO_WAIT_CBSUSPEND 00400000 /* aio_suspend waiting for callback */
+#define LIO_WAIT_SIGSUSPEND 01000000 /* aio_suspend waiting for signal */
+#define LIO_WAIT_ATYPES 01760000 /* all async wait types, except nowait */
+#define LIO_WAIT_TYPES 00020000 /* all sync wait types (sorta) */
+#endif /* sgi */
+#if defined(__sun) || defined(__hpux) || defined(_AIX)
+#define LIO_WAIT_TYPES 00300000 /* all wait types, except nowait */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_WAIT_TYPES 00360000 /* all wait types, except nowait */
+#endif /* CRAY */
+
+/* meta wait io */
+/* 00 000 0000 */
+
+#if defined(sgi) || defined(__linux__)
+/* all callback wait types */
+#define LIO_WAIT_CBTYPES (LIO_WAIT_CBSUSPEND)
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE|LIO_WAIT_SIGSUSPEND)
+/* all aio_{read,write} or lio_listio */
+#define LIO_IO_ASYNC_TYPES (LIO_IO_ASYNC|LIO_IO_SLISTIO|LIO_IO_ALISTIO)
+#endif /* sgi */
+#if defined(__sun) || defined(__hpux) || defined(_AIX)
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE)
+#endif /* linux */
+#ifdef CRAY
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE)
+#endif /* CRAY */
+
+/*
+ * This bit provides a way to randomly pick an io type and wait method.
+ * lio_read_buffer() and lio_write_buffer() functions will call
+ * lio_random_methods() with the given method.
+ */
+#define LIO_RANDOM 010000000
+
+/*
+ * This bit provides a way for the programmer to use async i/o with
+ * signals and to use their own signal handler. By default,
+ * the signal will only be given to the system call if the wait
+ * method is LIO_WAIT_SIGPAUSE or LIO_WAIT_SIGACTIVE.
+ * Whenever these wait methods are used, libio signal handler
+ * will be used.
+ */
+#define LIO_USE_SIGNAL 020000000
+
+/*
+ * prototypes/structures for functions in the libio.c module. See comments
+ * in that module, or man page entries for information on the individual
+ * functions.
+ */
+
+int stride_bounds(int offset, int stride, int nstrides,
+ int bytes_per_stride, int *min_byte, int *max_byte);
+
+int lio_set_debug(int level);
+int lio_parse_io_arg1(char *string);
+void lio_help1(char *prefex);
+int lio_parse_io_arg2(char *string, char **badtoken);
+void lio_help2(char *prefex);
+int lio_write_buffer(int fd, int method, char *buffer, int size,
+ int sig, char **errmsg, long wrd);
+
+int lio_read_buffer(int fd, int method, char *buffer, int size,
+ int sig, char **errmsg, long wrd);
+int lio_random_methods(long mask);
+
+#if CRAY
+#include <sys/iosw.h>
+int lio_wait4asyncio(int method, int fd, struct iosw **statptr);
+int lio_check_asyncio(char *io_type, int size, struct iosw *status);
+#endif /* CRAY */
+#if defined (sgi)
+#include <aio.h>
+int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp);
+int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method);
+#endif /* sgi */
+#if defined(__linux__) && !defined(__UCLIBC__)
+#include <aio.h>
+int lio_wait4asyncio(int method, int fd, struct aiocb *aiocbp);
+int lio_check_asyncio(char *io_type, int size, struct aiocb *aiocbp, int method);
+#endif
+
+/*
+ * Define the structure that contains the infomation that is used
+ * by the parsing and help functions.
+ */
+struct lio_info_type {
+ char *token;
+ int bits;
+ char *desc;
+};
+
+
diff --git a/src/kernel/tests/include/old/usctest.h b/src/kernel/tests/include/old/usctest.h
new file mode 100644
index 0000000..9b9446d
--- /dev/null
+++ b/src/kernel/tests/include/old/usctest.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Author: William Roske
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+#ifndef __USCTEST_H__
+#define __USCTEST_H__
+
+/*
+ * Ensure that PATH_MAX is defined
+ */
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/***********************************************************************
+ * The following globals are defined in parse_opts.c but must be
+ * externed here because they are used in the macros defined below.
+ ***********************************************************************/
+extern int STD_LOOP_COUNT; /* changed by -in to set loop count to n */
+
+extern long TEST_RETURN;
+extern int TEST_ERRNO;
+
+/***********************************************************************
+ * TEST: calls a system call
+ *
+ * parameters:
+ * SCALL = system call and parameters to execute
+ *
+ ***********************************************************************/
+#define TEST(SCALL) \
+ do { \
+ errno = 0; \
+ TEST_RETURN = SCALL; \
+ TEST_ERRNO = errno; \
+ } while (0)
+
+/***********************************************************************
+ * TEST_VOID: calls a system call
+ *
+ * parameters:
+ * SCALL = system call and parameters to execute
+ *
+ * Note: This is IDENTICAL to the TEST() macro except that it is intended
+ * for use with syscalls returning no values (void syscall()). The
+ * Typecasting nothing (void) into an unsigned integer causes compilation
+ * errors.
+ *
+ ***********************************************************************/
+#define TEST_VOID(SCALL) do { errno = 0; SCALL; TEST_ERRNO = errno; } while (0)
+
+/***********************************************************************
+ * TEST_PAUSE: Pause for SIGUSR1 if the pause flag is set.
+ * Just continue when signal comes in.
+ *
+ * parameters:
+ * none
+ *
+ ***********************************************************************/
+#define TEST_PAUSE usc_global_setup_hook();
+int usc_global_setup_hook();
+
+/***********************************************************************
+ * TEST_LOOPING now call the usc_test_looping function.
+ * The function will return 1 if the test should continue
+ * iterating.
+ *
+ ***********************************************************************/
+#define TEST_LOOPING usc_test_looping
+int usc_test_looping(int counter);
+
+#endif /* __USCTEST_H__ */
diff --git a/src/kernel/tests/include/parse_vdso.h b/src/kernel/tests/include/parse_vdso.h
new file mode 100644
index 0000000..5212fc6
--- /dev/null
+++ b/src/kernel/tests/include/parse_vdso.h
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Linaro Limited. All rights reserved.
+ * Author: Viresh Kumar <viresh.kumar@linaro.org>
+ */
+
+#ifndef PARSE_VDSO_H__
+#define PARSE_VDSO_H__
+
+#include <stdint.h>
+
+/*
+ * To use this vDSO parser, first call one of the vdso_init_* functions.
+ * If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR
+ * to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv.
+ * Then call vdso_sym for each symbol you want. For example, to look up
+ * gettimeofday on x86_64, use:
+ *
+ * <some pointer> = vdso_sym("LINUX_2.6", "gettimeofday");
+ * or
+ * <some pointer> = vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
+ *
+ * vdso_sym will return 0 if the symbol doesn't exist or if the init function
+ * failed or was not called. vdso_sym is a little slow, so its return value
+ * should be cached.
+ *
+ * vdso_sym is threadsafe; the init functions are not.
+ *
+ * These are the prototypes:
+ */
+
+#include <time.h>
+
+extern void vdso_init_from_auxv(void *auxv);
+extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
+extern void *vdso_sym(const char *version, const char *name);
+
+typedef int (*gettime_t)(clockid_t clk_id, void *ts);
+void find_clock_gettime_vdso(gettime_t *ptr_vdso_gettime,
+ gettime_t *ptr_vdso_gettime64);
+#endif /* PARSE_VDSO_H__ */
diff --git a/src/kernel/tests/include/safe_file_ops_fn.h b/src/kernel/tests/include/safe_file_ops_fn.h
new file mode 100644
index 0000000..052fb1b
--- /dev/null
+++ b/src/kernel/tests/include/safe_file_ops_fn.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SAFE_FILE_OPS_FN
+#define SAFE_FILE_OPS_FN
+
+#include <sys/stat.h>
+#include <time.h>
+
+#include "lapi/utime.h"
+
+/*
+ * All-in-one function to scanf value(s) from a file.
+ */
+int file_scanf(const char *file, const int lineno,
+ const char *path, const char *fmt, ...)
+ __attribute__ ((format (scanf, 4, 5)));
+
+void safe_file_scanf(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *path, const char *fmt, ...)
+ __attribute__ ((format (scanf, 5, 6)));
+
+int file_lines_scanf(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int strict,
+ const char *path, const char *fmt, ...)
+ __attribute__ ((format (scanf, 6, 7)));
+
+/*
+ * All-in-one function that lets you printf directly into a file.
+ */
+int file_printf(const char *file, const int lineno,
+ const char *path, const char *fmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+void safe_file_printf(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *path, const char *fmt, ...)
+ __attribute__ ((format (printf, 5, 6)));
+
+/*
+ * Safe function to copy files, no more system("cp ...") please.
+ */
+void safe_cp(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *src, const char *dst);
+
+/*
+ * Safe function to touch a file.
+ *
+ * If the file (pathname) does not exist It will be created with
+ * the specified permission (mode) and the access/modification times (times).
+ *
+ * If mode is 0 then the file is created with (0666 & ~umask)
+ * permission or (if the file exists) the permission is not changed.
+ *
+ * times is a timespec[2] (as for utimensat(2)). If times is NULL then
+ * the access/modification times of the file is set to the current time.
+ */
+void safe_touch(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *pathname,
+ mode_t mode, const struct timespec times[2]);
+
+/* helper functions to setup overlayfs mountpoint */
+void create_overlay_dirs(void);
+int mount_overlay(const char *file, const int lineno, int skip);
+
+#endif /* SAFE_FILE_OPS_FN */
diff --git a/src/kernel/tests/include/safe_macros_fn.h b/src/kernel/tests/include/safe_macros_fn.h
new file mode 100644
index 0000000..3df9528
--- /dev/null
+++ b/src/kernel/tests/include/safe_macros_fn.h
@@ -0,0 +1,187 @@
+/*
+ * Safe macros for commonly used syscalls to reduce code duplication in LTP
+ * testcases, and to ensure all errors are caught in said testcases as
+ * gracefully as possible.
+ *
+ * Also satiates some versions of gcc/glibc when the warn_unused_result
+ * attribute is applied to the function call.
+ *
+ * Licensed under the GPLv2.
+ */
+
+#ifndef SAFE_MACROS_FN_H__
+#define SAFE_MACROS_FN_H__
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h>
+
+char* safe_basename(const char *file, const int lineno,
+ void (*cleanup_fn)(void), char *path);
+
+int safe_chdir(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *path);
+
+int safe_close(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int fildes);
+
+int safe_creat(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname, mode_t mode);
+
+char* safe_dirname(const char *file, const int lineno,
+ void (*cleanup_fn)(void), char *path);
+
+char* safe_getcwd(const char *file, const int lineno,
+ void (*cleanup_fn)(void), char *buf, size_t size);
+
+struct passwd* safe_getpwnam(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *name);
+
+int safe_getrusage(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int who, struct rusage *usage);
+
+void* safe_malloc(const char *file, const int lineno,
+ void (*cleanup_fn)(void), size_t size);
+
+int safe_mkdir(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname, mode_t mode);
+
+int safe_rmdir(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname);
+
+
+int safe_munmap(const char *file, const int lineno,
+ void (*cleanup_fn)(void), void *addr, size_t length);
+
+int safe_open(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname, int oflags, ...);
+
+int safe_pipe(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int fildes[2]);
+
+ssize_t safe_read(const char *file, const int lineno,
+ void (*cleanup_fn)(void), char len_strict, int fildes,
+ void *buf, size_t nbyte);
+
+int safe_setegid(const char *file, const int lineno,
+ void (*cleanup_fn)(void), gid_t egid);
+
+int safe_seteuid(const char *file, const int lineno,
+ void (*cleanup_fn)(void), uid_t euid);
+
+int safe_setgid(const char *file, const int lineno,
+ void (*cleanup_fn)(void), gid_t gid);
+
+int safe_setuid(const char *file, const int lineno,
+ void (*cleanup_fn)(void), uid_t uid);
+
+int safe_getresuid(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ uid_t *ruid, uid_t *euid, uid_t *suid);
+
+int safe_getresgid(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ gid_t *rgid, gid_t *egid, gid_t *sgid);
+
+int safe_unlink(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname);
+
+int safe_link(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *oldpath,
+ const char *newpath);
+
+int safe_linkat(const char *file, const int lineno,
+ void (cleanup_fn)(void), int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, int flags);
+
+ssize_t safe_readlink(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *path,
+ char *buf, size_t bufsize);
+
+int safe_symlink(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *oldpath,
+ const char *newpath);
+
+ssize_t safe_write(const char *file, const int lineno,
+ void (cleanup_fn)(void), char len_strict, int fildes,
+ const void *buf, size_t nbyte);
+
+long safe_strtol(const char *file, const int lineno,
+ void (cleanup_fn)(void), char *str, long min, long max);
+
+unsigned long safe_strtoul(const char *file, const int lineno,
+ void (cleanup_fn)(void),
+ char *str, unsigned long min, unsigned long max);
+
+long safe_sysconf(const char *file, const int lineno,
+ void (cleanup_fn)(void), int name);
+
+int safe_chmod(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, mode_t mode);
+
+int safe_fchmod(const char *file, const int lineno, void (cleanup_fn)(void),
+ int fd, mode_t mode);
+
+int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, uid_t owner, gid_t group);
+
+int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void),
+ int fd, uid_t owner, gid_t group);
+
+pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void),
+ int *status);
+
+pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void),
+ pid_t pid, int *status, int opts);
+
+int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void),
+ pid_t pid, int sig);
+
+void *safe_memalign(const char *file, const int lineno,
+ void (*cleanup_fn)(void), size_t alignment, size_t size);
+
+int safe_mkfifo(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname, mode_t mode);
+
+int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *oldpath, const char *newpath);
+
+int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *source, const char *target,
+ const char *filesystemtype, unsigned long mountflags,
+ const void *data);
+
+int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *target);
+
+DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *name);
+
+int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void),
+ DIR *dirp);
+
+struct dirent *safe_readdir(const char *file, const int lineno,
+ void (cleanup_fn)(void),
+ DIR *dirp);
+
+DIR* safe_opendir(const char *file, const int lineno,
+ void (cleanup_fn)(void),
+ const char *name);
+
+struct dirent *safe_readdir(const char *file, const int lineno,
+ void (cleanup_fn)(void),
+ DIR *dirp);
+
+int safe_closedir(const char *file, const int lineno,
+ void (cleanup_fn)(void),
+ DIR *dirp);
+
+#endif /* SAFE_MACROS_FN_H__ */
diff --git a/src/kernel/tests/include/safe_net_fn.h b/src/kernel/tests/include/safe_net_fn.h
new file mode 100644
index 0000000..2fda11f
--- /dev/null
+++ b/src/kernel/tests/include/safe_net_fn.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ * Copyright (c) 2015 Fujitsu Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SAFE_NET_FN_H__
+#define SAFE_NET_FN_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+
+int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
+ int domain, int type, int protocol);
+
+int safe_socketpair(const char *file, const int lineno, int domain, int type,
+ int protocol, int sv[]);
+
+int safe_getsockopt(const char *file, const int lineno, int sockfd, int level,
+ int optname, void *optval, socklen_t *optlen);
+
+int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
+ int optname, const void *optval, socklen_t optlen);
+
+ssize_t safe_send(const char *file, const int lineno, char len_strict,
+ int sockfd, const void *buf, size_t len, int flags);
+
+ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
+ int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen);
+
+ssize_t safe_sendmsg(const char *file, const int lineno, size_t msg_len,
+ int sockfd, const struct msghdr *msg, int flags);
+
+ssize_t safe_recvmsg(const char *file, const int lineno, size_t msg_len,
+ int sockfd, struct msghdr *msg, int flags);
+
+int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
+ int socket, const struct sockaddr *address,
+ socklen_t address_len);
+
+int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
+ int socket, int backlog);
+
+int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void),
+ int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
+ int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+int safe_getsockname(const char *file, const int lineno,
+ void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
+ socklen_t *addrlen);
+
+int safe_gethostname(const char *file, const int lineno,
+ char *name, size_t size);
+
+int tst_getsockport(const char *file, const int lineno, int sockfd);
+
+unsigned short tst_get_unused_port(const char *file, const int lineno,
+ void (cleanup_fn)(void), unsigned short family, int type);
+
+char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res,
+ size_t len);
+
+#endif /* SAFE_NET_FN_H__ */
diff --git a/src/kernel/tests/include/safe_stdio_fn.h b/src/kernel/tests/include/safe_stdio_fn.h
new file mode 100644
index 0000000..3818a86
--- /dev/null
+++ b/src/kernel/tests/include/safe_stdio_fn.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SAFE_STDIO_FN_H__
+#define SAFE_STDIO_FN_H__
+
+#include <stdio.h>
+
+FILE *safe_fopen(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, const char *mode);
+
+int safe_fclose(const char *file, const int lineno, void (cleanup_fn)(void),
+ FILE *f);
+
+int safe_asprintf(const char *file, const int lineno, void (cleanup_fn)(void),
+ char **strp, const char *fmt, ...);
+
+FILE *safe_popen(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *command, const char *type);
+
+#endif /* SAFE_STDIO_FN_H__ */
diff --git a/src/kernel/tests/include/tst_af_alg.h b/src/kernel/tests/include/tst_af_alg.h
new file mode 100644
index 0000000..fd2ff06
--- /dev/null
+++ b/src/kernel/tests/include/tst_af_alg.h
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+/**
+ * @file tst_af_alg.h
+ *
+ * Library for accessing kernel crypto algorithms via AF_ALG.
+ *
+ * See https://www.kernel.org/doc/html/latest/crypto/userspace-if.html
+ * for more information about AF_ALG.
+ */
+
+#ifndef TST_AF_ALG_H
+#define TST_AF_ALG_H
+
+#include "lapi/if_alg.h"
+#include <stdbool.h>
+
+/**
+ * Create an AF_ALG algorithm socket.
+ *
+ * This creates an AF_ALG algorithm socket that is initially not bound to any
+ * particular algorithm. On failure, tst_brk() is called with TCONF if the
+ * kernel doesn't support AF_ALG, otherwise TBROK.
+ *
+ * @return a new AF_ALG algorithm socket
+ */
+int tst_alg_create(void);
+
+/**
+ * Bind an AF_ALG algorithm socket to an algorithm.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param addr A structure which specifies the algorithm to use
+ *
+ * On failure, tst_brk() is called with TCONF if the kernel doesn't support the
+ * specified algorithm, otherwise TBROK.
+ */
+void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr);
+
+/**
+ * Bind an AF_ALG algorithm socket to an algorithm.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * Like tst_alg_bind_addr(), except this just takes in the algorithm type and
+ * name. The 'feat' and 'mask' fields are left 0.
+ *
+ * On failure, tst_brk() is called with TCONF if the kernel doesn't support the
+ * specified algorithm, otherwise TBROK.
+ */
+void tst_alg_bind(int algfd, const char *algtype, const char *algname);
+
+/**
+ * Check for the availability of an algorithm.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * Return true if the algorithm is available, or false if unavailable.
+ * If another error occurs, tst_brk() is called with TBROK.
+ */
+bool tst_have_alg(const char *algtype, const char *algname);
+
+/**
+ * Require the availability of an algorithm.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ *
+ * If the algorithm is unavailable, tst_brk() is called with TCONF.
+ * If another error occurs, tst_brk() is called with TBROK.
+ */
+void tst_require_alg(const char *algtype, const char *algname);
+
+/**
+ * Assign a cryptographic key to an AF_ALG algorithm socket.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ * @param key Pointer to the key. If NULL, a random key is generated.
+ * @param keylen Length of the key in bytes
+ *
+ * On failure, tst_brk() is called with TBROK.
+ */
+void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen);
+
+/**
+ * Create an AF_ALG request socket for the given algorithm socket.
+ *
+ * @param algfd An AF_ALG algorithm socket
+ *
+ * This creates a request socket for the given algorithm socket, which must be
+ * bound to an algorithm. The same algorithm socket can have many request
+ * sockets used concurrently to perform independent cryptographic operations,
+ * e.g. hashing or encryption/decryption. But the key, if any, that has been
+ * assigned to the algorithm is shared by all request sockets.
+ *
+ * On failure, tst_brk() is called with TBROK.
+ *
+ * @return a new AF_ALG request socket
+ */
+int tst_alg_accept(int algfd);
+
+/**
+ * Set up an AF_ALG algorithm socket for the given algorithm w/ given key.
+ *
+ * @param algtype The type of algorithm, such as "hash" or "skcipher"
+ * @param algname The name of the algorithm, such as "sha256" or "xts(aes)"
+ * @param key The key to use (optional)
+ * @param keylen The length of the key in bytes (optional)
+ *
+ * This is a helper function which creates an AF_ALG algorithm socket, binds it
+ * to the specified algorithm, and optionally sets a key. If keylen is 0 then
+ * no key is set; otherwise if key is NULL a key of the given length is randomly
+ * generated and set; otherwise the given key is set.
+ *
+ * @return the AF_ALG algorithm socket that was set up
+ */
+int tst_alg_setup(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen);
+
+/**
+ * Set up an AF_ALG request socket for the given algorithm w/ given key.
+ *
+ * This is like tst_alg_setup(), except this returns a request fd instead of the
+ * alg fd. The alg fd is closed, so it doesn't need to be kept track of.
+ *
+ * @return the AF_ALG request socket that was set up
+ */
+int tst_alg_setup_reqfd(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen);
+
+/** Specification of control data to send to an AF_ALG request socket */
+struct tst_alg_sendmsg_params {
+
+ /** If true, send ALG_SET_OP with ALG_OP_ENCRYPT */
+ bool encrypt;
+
+ /** If true, send ALG_SET_OP with ALG_OP_DECRYPT */
+ bool decrypt;
+
+ /** If ivlen != 0, send ALG_SET_IV */
+ const uint8_t *iv;
+ unsigned int ivlen;
+
+ /** If assoclen != 0, send ALG_SET_AEAD_ASSOCLEN */
+ unsigned int assoclen;
+
+ /* Value to use as msghdr::msg_flags */
+ uint32_t msg_flags;
+};
+
+/**
+ * Send some data to an AF_ALG request socket, including control data.
+ * @param reqfd An AF_ALG request socket
+ * @param data The data to send
+ * @param datalen The length of data in bytes
+ * @param params Specification of the control data to send
+ *
+ * On failure, tst_brk() is called with TBROK.
+ */
+void tst_alg_sendmsg(int reqfd, const void *data, size_t datalen,
+ const struct tst_alg_sendmsg_params *params);
+
+#endif /* TST_AF_ALG_H */
diff --git a/src/kernel/tests/include/tst_ansi_color.h b/src/kernel/tests/include/tst_ansi_color.h
new file mode 100644
index 0000000..770bf46
--- /dev/null
+++ b/src/kernel/tests/include/tst_ansi_color.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef TST_ANSI_COLOR_H__
+#define TST_ANSI_COLOR_H__
+/*
+ * NOTE: these colors should match colors defined in tst_flag2color() in
+ * testcases/lib/tst_ansi_color.sh
+ */
+#define ANSI_COLOR_BLUE "\033[1;34m"
+#define ANSI_COLOR_GREEN "\033[1;32m"
+#define ANSI_COLOR_MAGENTA "\033[1;35m"
+#define ANSI_COLOR_RED "\033[1;31m"
+#define ANSI_COLOR_YELLOW "\033[1;33m"
+
+#define ANSI_COLOR_RESET "\033[0m"
+
+char* tst_ttype2color(int ttype);
+int tst_color_enabled(int fd);
+
+#endif /* TST_ANSI_COLOR_H__ */
diff --git a/src/kernel/tests/include/tst_assert.h b/src/kernel/tests/include/tst_assert.h
new file mode 100644
index 0000000..dcb62df
--- /dev/null
+++ b/src/kernel/tests/include/tst_assert.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+#ifndef TST_ASSERT_H__
+#define TST_ASSERT_H__
+
+#define TST_ASSERT_INT(path, val) \
+ tst_assert_int(__FILE__, __LINE__, path, val)
+
+/*
+ * Asserts that integer value stored in file pointed by path equals to the
+ * value passed to this function. This is mostly useful for asserting correct
+ * values in sysfs, procfs, etc.
+ */
+void tst_assert_int(const char *file, const int lineno,
+ const char *path, int val);
+
+#define TST_ASSERT_FILE_INT(path, prefix, val) \
+ tst_assert_file_int(__FILE__, __LINE__, path, prefix, val)
+
+/*
+ * Same as tst_assert_int() but for unsigned long.
+ */
+void tst_assert_ulong(const char *file, const int lineno,
+ const char *path, unsigned long val);
+
+#define TST_ASSERT_ULONG(path, val) \
+ tst_assert_ulong(__FILE__, __LINE__, path, val)
+
+/*
+ * Asserts that integer value stored in the prefix field of file pointed by path
+ * equals to the value passed to this function. This is mostly useful for
+ * asserting correct field values in sysfs, procfs, etc.
+ */
+
+void tst_assert_file_int(const char *file, const int lineno,
+ const char *path, const char *prefix, int val);
+
+
+#define TST_ASSERT_STR(path, val) \
+ tst_assert_str(__FILE__, __LINE__, path, val)
+
+/*
+ * Asserts that a string value stored in file pointed by path equals to the
+ * value passed to this function. This is mostly useful for asserting correct
+ * values in sysfs, procfs, etc.
+ */
+void tst_assert_str(const char *file, const int lineno,
+ const char *path, const char *val);
+
+#define TST_ASSERT_FILE_STR(path, prefix, val) \
+ tst_assert_file_str(__FILE__, __LINE__, path, prefix, val)
+
+/*
+ * Asserts that a string value stored in the prefix field of file pointed by path
+ * equals to the value passed to this function. This is mostly useful for
+ * asserting correct field values in sysfs, procfs, etc.
+ */
+void tst_assert_file_str(const char *file, const int lineno,
+ const char *path, const char *prefix, const char *val);
+
+#endif /* TST_ASSERT_H__ */
diff --git a/src/kernel/tests/include/tst_atomic.h b/src/kernel/tests/include/tst_atomic.h
new file mode 100644
index 0000000..061cd3d
--- /dev/null
+++ b/src/kernel/tests/include/tst_atomic.h
@@ -0,0 +1,334 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/* The LTP library has some of its own atomic synchronisation primitives
+ * contained in this file. Generally speaking these should not be used
+ * directly in tests for synchronisation, instead use tst_checkpoint.h,
+ * tst_fuzzy_sync.h or the POSIX library.
+ *
+ * Notes on compile and runtime memory barriers and atomics.
+ *
+ * Within the LTP library we have three concerns when accessing variables
+ * shared by multiple threads or processes:
+ *
+ * (1) Removal or reordering of accesses by the compiler.
+ * (2) Atomicity of addition.
+ * (3) LOAD-STORE ordering between threads.
+ *
+ * The first (1) is the most likely to cause an error if not properly
+ * handled. We avoid it by using volatile variables and statements which will
+ * not be removed or reordered by the compiler during optimisation. This includes
+ * the __atomic and __sync intrinsics and volatile asm statements marked with
+ * "memory" as well as variables marked with volatile.
+ *
+ * On any platform Linux is likely to run on, a LOAD (fetch) or STORE of a
+ * 32-bit integer will be atomic. However fetching and adding to a variable is
+ * quite likely not; so for (2) we need to ensure we use atomic addition.
+ *
+ * Finally, for tst_fuzzy_sync at least, we need to ensure that LOADs and
+ * STOREs of any shared variables (including non-atomics) that are made
+ * between calls to tst_fzsync_wait are completed (globally visible) before
+ * tst_fzsync_wait completes. For this, runtime memory and instruction
+ * barriers are required in addition to compile time.
+ *
+ * We use full sequential ordering (__ATOMIC_SEQ_CST) for the sake of
+ * simplicity. LTP tests tend to be syscall heavy so any performance gain from
+ * using a weaker memory model is unlikely to result in a relatively large
+ * performance improvement while at the same time being a potent source of
+ * confusion.
+ *
+ * Likewise, for the fallback ASM, the simplest "definitely will work, always"
+ * approach is preferred over anything more performant.
+ *
+ * Also see Documentation/memory-barriers.txt in the kernel tree and
+ * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
+ * terminology may vary between sources.
+ */
+
+#ifndef TST_ATOMIC_H__
+#define TST_ATOMIC_H__
+
+#include "config.h"
+
+#if HAVE_ATOMIC_MEMORY_MODEL == 1
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ return __atomic_add_fetch(v, i, __ATOMIC_SEQ_CST);
+}
+
+static inline int tst_atomic_load(int *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ __atomic_store_n(v, i, __ATOMIC_SEQ_CST);
+}
+
+#elif HAVE_SYNC_ADD_AND_FETCH == 1
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ return __sync_add_and_fetch(v, i);
+}
+
+static inline int tst_atomic_load(int *v)
+{
+ int ret;
+
+ __sync_synchronize();
+ ret = *v;
+ __sync_synchronize();
+ return ret;
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ __sync_synchronize();
+ *v = i;
+ __sync_synchronize();
+}
+
+#elif defined(__i386__) || defined(__x86_64__)
+# define LTP_USE_GENERIC_LOAD_STORE_ASM 1
+
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ int __ret = i;
+
+ /*
+ * taken from arch/x86/include/asm/cmpxchg.h
+ */
+ asm volatile ("lock; xaddl %0, %1\n"
+ : "+r" (__ret), "+m" (*v) : : "memory", "cc");
+
+ return i + __ret;
+}
+
+#elif defined(__powerpc__) || defined(__powerpc64__)
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ int t;
+
+ /* taken from arch/powerpc/include/asm/atomic.h */
+ asm volatile(
+ " sync\n"
+ "1: lwarx %0,0,%2 # atomic_add_return\n"
+ " add %0,%1,%0\n"
+ " stwcx. %0,0,%2 \n"
+ " bne- 1b\n"
+ " sync\n"
+ : "=&r" (t)
+ : "r" (i), "r" (v)
+ : "cc", "memory");
+
+ return t;
+}
+
+static inline int tst_atomic_load(int *v)
+{
+ int ret;
+
+ asm volatile("sync\n" : : : "memory");
+ ret = *v;
+ asm volatile("sync\n" : : : "memory");
+
+ return ret;
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ asm volatile("sync\n" : : : "memory");
+ *v = i;
+ asm volatile("sync\n" : : : "memory");
+}
+
+#elif defined(__s390__) || defined(__s390x__)
+# define LTP_USE_GENERIC_LOAD_STORE_ASM 1
+
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ int old_val, new_val;
+
+ /* taken from arch/s390/include/asm/atomic.h */
+ asm volatile(
+ " l %0,%2\n"
+ "0: lr %1,%0\n"
+ " ar %1,%3\n"
+ " cs %0,%1,%2\n"
+ " jl 0b"
+ : "=&d" (old_val), "=&d" (new_val), "+Q" (*v)
+ : "d" (i)
+ : "cc", "memory");
+
+ return old_val + i;
+}
+
+#elif defined(__arc__)
+
+/*ARCv2 defines the smp barriers */
+#ifdef __ARC700__
+#define smp_mb() asm volatile("" : : : "memory")
+#else
+#define smp_mb() asm volatile("dmb 3\n" : : : "memory")
+#endif
+
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ unsigned int val;
+
+ smp_mb();
+
+ asm volatile(
+ "1: llock %[val], [%[ctr]] \n"
+ " add %[val], %[val], %[i] \n"
+ " scond %[val], [%[ctr]] \n"
+ " bnz 1b \n"
+ : [val] "=&r" (val)
+ : [ctr] "r" (v),
+ [i] "ir" (i)
+ : "cc", "memory");
+
+ smp_mb();
+
+ return val;
+}
+
+static inline int tst_atomic_load(int *v)
+{
+ int ret;
+
+ smp_mb();
+ ret = *v;
+ smp_mb();
+
+ return ret;
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ smp_mb();
+ *v = i;
+ smp_mb();
+}
+
+#elif defined (__aarch64__)
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ unsigned long tmp;
+ int result;
+
+ __asm__ __volatile__(
+" prfm pstl1strm, %2 \n"
+"1: ldaxr %w0, %2 \n"
+" add %w0, %w0, %w3 \n"
+" stlxr %w1, %w0, %2 \n"
+" cbnz %w1, 1b \n"
+" dmb ish \n"
+ : "=&r" (result), "=&r" (tmp), "+Q" (*v)
+ : "Ir" (i)
+ : "memory");
+
+ return result;
+}
+
+/* We are using load and store exclusive (ldaxr & stlxr) instructions to try
+ * and help prevent the tst_atomic_load and, more likely, tst_atomic_store
+ * functions from interfering with tst_atomic_add_return which takes advantage
+ * of exclusivity. It is not clear if this is a good idea or not, but does
+ * mean that all three functions are very similar.
+ */
+static inline int tst_atomic_load(int *v)
+{
+ int ret;
+ unsigned long tmp;
+
+ asm volatile("//atomic_load \n"
+ " prfm pstl1strm, %[v] \n"
+ "1: ldaxr %w[ret], %[v] \n"
+ " stlxr %w[tmp], %w[ret], %[v] \n"
+ " cbnz %w[tmp], 1b \n"
+ " dmb ish \n"
+ : [tmp] "=&r" (tmp), [ret] "=&r" (ret), [v] "+Q" (*v)
+ : : "memory");
+
+ return ret;
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ unsigned long tmp;
+
+ asm volatile("//atomic_store \n"
+ " prfm pstl1strm, %[v] \n"
+ "1: ldaxr %w[tmp], %[v] \n"
+ " stlxr %w[tmp], %w[i], %[v] \n"
+ " cbnz %w[tmp], 1b \n"
+ " dmb ish \n"
+ : [tmp] "=&r" (tmp), [v] "+Q" (*v)
+ : [i] "r" (i)
+ : "memory");
+}
+
+#elif defined(__sparc__) && defined(__arch64__)
+# define LTP_USE_GENERIC_LOAD_STORE_ASM 1
+static inline int tst_atomic_add_return(int i, int *v)
+{
+ int ret, tmp;
+
+ /* Based on arch/sparc/lib/atomic_64.S with the exponential backoff
+ * function removed because we are unlikely to have a large (>= 16?)
+ * number of cores continuously trying to update one variable.
+ */
+ asm volatile("/*atomic_add_return*/ \n"
+ "1: ldsw [%[v]], %[ret]; \n"
+ " add %[ret], %[i], %[tmp]; \n"
+ " cas [%[v]], %[ret], %[tmp]; \n"
+ " cmp %[ret], %[tmp]; \n"
+ " bne,pn %%icc, 1b; \n"
+ " nop; \n"
+ " add %[ret], %[i], %[ret]; \n"
+ : [ret] "=r&" (ret), [tmp] "=r&" (tmp)
+ : [i] "r" (i), [v] "r" (v)
+ : "memory", "cc");
+
+ return ret;
+}
+
+#else /* HAVE_SYNC_ADD_AND_FETCH == 1 */
+# error Your compiler does not provide __atomic_add_fetch, __sync_add_and_fetch \
+ and an LTP implementation is missing for your architecture.
+#endif
+
+#ifdef LTP_USE_GENERIC_LOAD_STORE_ASM
+static inline int tst_atomic_load(int *v)
+{
+ int ret;
+
+ asm volatile("" : : : "memory");
+ ret = *v;
+ asm volatile("" : : : "memory");
+
+ return ret;
+}
+
+static inline void tst_atomic_store(int i, int *v)
+{
+ asm volatile("" : : : "memory");
+ *v = i;
+ asm volatile("" : : : "memory");
+}
+#endif
+
+static inline int tst_atomic_inc(int *v)
+{
+ return tst_atomic_add_return(1, v);
+}
+
+static inline int tst_atomic_dec(int *v)
+{
+ return tst_atomic_add_return(-1, v);
+}
+
+#endif /* TST_ATOMIC_H__ */
diff --git a/src/kernel/tests/include/tst_buffers.h b/src/kernel/tests/include/tst_buffers.h
new file mode 100644
index 0000000..d19ac8c
--- /dev/null
+++ b/src/kernel/tests/include/tst_buffers.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_BUFFERS_H__
+#define TST_BUFFERS_H__
+
+/*
+ * Buffer description consist of a pointer to a pointer and buffer type/size
+ * encoded as a different structure members.
+ *
+ * Only one of the size and iov_sizes can be set at a time.
+ */
+struct tst_buffers {
+ /*
+ * This pointer points to a buffer pointer.
+ */
+ void *ptr;
+ /*
+ * Buffer size.
+ */
+ size_t size;
+ /*
+ * Array of iov buffer sizes terminated by -1.
+ */
+ int *iov_sizes;
+};
+
+/*
+ * Allocates buffers based on the tst_buffers structure.
+ *
+ * @bufs NULL terminated array of test buffer descriptions.
+ *
+ * This is called from the test library if the tst_test->bufs pointer is set.
+ */
+void tst_buffers_alloc(struct tst_buffers bufs[]);
+
+/*
+ * strdup() that callls tst_alloc().
+ */
+char *tst_strdup(const char *str);
+
+/*
+ * Allocates size bytes, returns pointer to the allocated buffer.
+ */
+void *tst_alloc(size_t size);
+
+/*
+ * Allocates iovec structure including the buffers.
+ *
+ * @sizes -1 terminated array of buffer sizes.
+ */
+struct iovec *tst_iovec_alloc(int sizes[]);
+
+/*
+ * Frees all allocated buffers.
+ *
+ * This is called at the end of the test automatically.
+ */
+void tst_free_all(void);
+
+#endif /* TST_BUFFERS_H__ */
diff --git a/src/kernel/tests/include/tst_capability.h b/src/kernel/tests/include/tst_capability.h
new file mode 100644
index 0000000..6067804
--- /dev/null
+++ b/src/kernel/tests/include/tst_capability.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+/**
+ * @file tst_capability.h
+ *
+ * Limited capability operations without libcap.
+ */
+
+#ifndef TST_CAPABILITY_H
+#define TST_CAPABILITY_H
+
+#include <stdint.h>
+
+#include "lapi/capability.h"
+
+#define TST_CAP_DROP 1
+#define TST_CAP_REQ (1 << 1)
+
+#define TST_CAP(action, capability) {action, capability, #capability}
+
+struct tst_cap_user_header {
+ uint32_t version;
+ int pid;
+};
+
+struct tst_cap_user_data {
+ uint32_t effective;
+ uint32_t permitted;
+ uint32_t inheritable;
+};
+
+struct tst_cap {
+ uint32_t action;
+ uint32_t id;
+ char *name;
+};
+
+/**
+ * Get the capabilities as decided by hdr.
+ *
+ * Note that the memory pointed to by data should be large enough to store two
+ * structs.
+ */
+int tst_capget(struct tst_cap_user_header *hdr,
+ struct tst_cap_user_data *data);
+
+/**
+ * Set the capabilities as decided by hdr and data
+ *
+ * Note that the memory pointed to by data should be large enough to store two
+ * structs.
+ */
+int tst_capset(struct tst_cap_user_header *hdr,
+ const struct tst_cap_user_data *data);
+
+/**
+ * Add, check or remove a capability
+ *
+ * It will attempt to drop or add capability to the effective set. It will
+ * try to detect if this is needed and whether it can or can't be done. If it
+ * clearly can not add a privilege to the effective set then it will return
+ * TCONF. However it may fail for some other reason and return TBROK.
+ *
+ * This only tries to change the effective set. Some tests may need to change
+ * the inheritable and ambient sets, so that child processes retain some
+ * capability.
+ */
+void tst_cap_action(struct tst_cap *cap);
+
+
+/**
+ * Add, check or remove a capabilities
+ *
+ * Takes a NULL terminated array of structs which describe whether some
+ * capabilities are needed or not and mask that determines subset of the
+ * actions to be performed. Loops over the array and if mask matches the
+ * element action it's passed to tst_cap_action().
+ */
+void tst_cap_setup(struct tst_cap *cap, unsigned int action_mask);
+
+#endif /* TST_CAPABILITY_H */
diff --git a/src/kernel/tests/include/tst_cgroup.h b/src/kernel/tests/include/tst_cgroup.h
new file mode 100644
index 0000000..77780e0
--- /dev/null
+++ b/src/kernel/tests/include/tst_cgroup.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ * Copyright (c) 2020 Li Wang <liwang@redhat.com>
+ */
+
+#ifndef TST_CGROUP_H
+#define TST_CGROUP_H
+
+#define PATH_TMP_CG_MEM "/tmp/cgroup_mem"
+#define PATH_TMP_CG_CST "/tmp/cgroup_cst"
+
+enum tst_cgroup_ver {
+ TST_CGROUP_V1 = 1,
+ TST_CGROUP_V2 = 2,
+};
+
+enum tst_cgroup_ctrl {
+ TST_CGROUP_MEMCG = 1,
+ TST_CGROUP_CPUSET = 2,
+ /* add cgroup controller */
+};
+
+enum tst_cgroup_ver tst_cgroup_version(void);
+
+/* To mount/umount specified cgroup controller on 'cgroup_dir' path */
+void tst_cgroup_mount(enum tst_cgroup_ctrl ctrl, const char *cgroup_dir);
+void tst_cgroup_umount(const char *cgroup_dir);
+
+/* To move current process PID to the mounted cgroup tasks */
+void tst_cgroup_move_current(const char *cgroup_dir);
+
+/* To set cgroup controller knob with new value */
+void tst_cgroup_set_knob(const char *cgroup_dir, const char *knob, long value);
+
+/* Set of functions to set knobs under the memory controller */
+void tst_cgroup_mem_set_maxbytes(const char *cgroup_dir, long memsz);
+int tst_cgroup_mem_swapacct_enabled(const char *cgroup_dir);
+void tst_cgroup_mem_set_maxswap(const char *cgroup_dir, long memsz);
+
+/* Set of functions to read/write cpuset controller files content */
+void tst_cgroup_cpuset_read_files(const char *cgroup_dir, const char *filename, char *retbuf);
+void tst_cgroup_cpuset_write_files(const char *cgroup_dir, const char *filename, const char *buf);
+
+#endif /* TST_CGROUP_H */
diff --git a/src/kernel/tests/include/tst_checkpoint.h b/src/kernel/tests/include/tst_checkpoint.h
new file mode 100644
index 0000000..5c8067d
--- /dev/null
+++ b/src/kernel/tests/include/tst_checkpoint.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_CHECKPOINT__
+#define TST_CHECKPOINT__
+
+#include "tst_checkpoint_fn.h"
+
+#define TST_CHECKPOINT_WAIT(id) \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0);
+
+#define TST_CHECKPOINT_WAIT2(id, msec_timeout) \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, msec_timeout);
+
+#define TST_CHECKPOINT_WAKE(id) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1);
+
+#define TST_CHECKPOINT_WAKE2(id, nr_wake) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, nr_wake);
+
+#define TST_CHECKPOINT_WAKE_AND_WAIT(id) \
+ tst_safe_checkpoint_wake(__FILE__, __LINE__, NULL, id, 1); \
+ tst_safe_checkpoint_wait(__FILE__, __LINE__, NULL, id, 0);
+
+extern const char *tst_ipc_path;
+
+#endif /* TST_CHECKPOINT__ */
diff --git a/src/kernel/tests/include/tst_checkpoint_fn.h b/src/kernel/tests/include/tst_checkpoint_fn.h
new file mode 100644
index 0000000..57db905
--- /dev/null
+++ b/src/kernel/tests/include/tst_checkpoint_fn.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_CHECKPOINT_FN__
+#define TST_CHECKPOINT_FN__
+
+/*
+ * Checkpoint initializaton, must be done first.
+ *
+ * NOTE: tst_tmpdir() must be called beforehand.
+ */
+void tst_checkpoint_init(const char *file, const int lineno,
+ void (*cleanup_fn)(void));
+
+/*
+ * Waits for wakeup.
+ *
+ * @id: Checkpoint id, possitive number
+ * @msec_timeout: Timeout in milliseconds, 0 == no timeout
+ */
+int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout);
+
+/*
+ * Wakes up sleeping process(es)/thread(s).
+ *
+ * @id: Checkpoint id, possitive number
+ * @nr_wake: Number of processes/threads to wake up
+ * @msec_timeout: Timeout in milliseconds, 0 == no timeout
+ */
+int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake,
+ unsigned int msec_timeout);
+
+void tst_safe_checkpoint_wait(const char *file, const int lineno,
+ void (*cleanup_fn)(void), unsigned int id,
+ unsigned int msec_timeout);
+
+void tst_safe_checkpoint_wake(const char *file, const int lineno,
+ void (*cleanup_fn)(void), unsigned int id,
+ unsigned int nr_wake);
+
+#endif /* TST_CHECKPOINT_FN__ */
diff --git a/src/kernel/tests/include/tst_checksum.h b/src/kernel/tests/include/tst_checksum.h
new file mode 100644
index 0000000..f062869
--- /dev/null
+++ b/src/kernel/tests/include/tst_checksum.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved.
+ */
+
+#ifndef TST_CHECKSUM_H__
+#define TST_CHECKSUM_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * Generates CRC32c checksum.
+ */
+uint32_t tst_crc32c(uint8_t *buf, size_t buf_len);
+
+#endif
diff --git a/src/kernel/tests/include/tst_clocks.h b/src/kernel/tests/include/tst_clocks.h
new file mode 100644
index 0000000..80030c6
--- /dev/null
+++ b/src/kernel/tests/include/tst_clocks.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * clock_gettime() and clock_getres() functions
+ */
+
+#ifndef TST_CLOCKS__
+#define TST_CLOCKS__
+
+int tst_clock_getres(clockid_t clk_id, struct timespec *res);
+
+int tst_clock_gettime(clockid_t clk_id, struct timespec *ts);
+
+int tst_clock_settime(clockid_t clk_id, struct timespec *ts);
+
+/*
+ * Converts clock id to a readable name.
+ */
+const char *tst_clock_name(clockid_t clk_id);
+
+#endif /* TST_CLOCKS__ */
diff --git a/src/kernel/tests/include/tst_clone.h b/src/kernel/tests/include/tst_clone.h
new file mode 100644
index 0000000..8818852
--- /dev/null
+++ b/src/kernel/tests/include/tst_clone.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef TST_CLONE_H__
+#define TST_CLONE_H__
+
+/* Functions from lib/cloner.c */
+int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg,
+ size_t stack_size, void *stack);
+int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg,
+ size_t stack_size, void *stack, ...);
+int ltp_clone_alloc(unsigned long clone_flags, int (*fn)(void *arg),
+ void *arg, size_t stacksize);
+int ltp_clone_quick(unsigned long clone_flags, int (*fn)(void *arg),
+ void *arg);
+void *ltp_alloc_stack(size_t size);
+
+#define clone(...) (use_the_ltp_clone_functions__do_not_use_clone)
+
+#endif /* TST_CLONE_H__ */
diff --git a/src/kernel/tests/include/tst_cmd.h b/src/kernel/tests/include/tst_cmd.h
new file mode 100644
index 0000000..1f39f69
--- /dev/null
+++ b/src/kernel/tests/include/tst_cmd.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_CMD_H__
+#define TST_CMD_H__
+
+enum tst_cmd_flags {
+ /*
+ * return the program exit code, otherwise it will call cleanup_fn() if the
+ * program exit code is not zero.
+ */
+ TST_CMD_PASS_RETVAL = 1,
+
+ /* exit with TCONF if program is not in path */
+ TST_CMD_TCONF_ON_MISSING = 2,
+};
+
+/*
+ * vfork() + execvp() specified program.
+ * @argv: a list of two (at least program name + NULL) or more pointers that
+ * represent the argument list to the new program. The array of pointers
+ * must be terminated by a NULL pointer.
+ * @stdout_fd: file descriptor where to redirect stdout. Set -1 if
+ * redirection is not needed.
+ * @stderr_fd: file descriptor where to redirect stderr. Set -1 if
+ * redirection is not needed.
+ * @flags: enum tst_cmd_flags
+ */
+int tst_cmd_fds_(void (cleanup_fn)(void),
+ const char *const argv[],
+ int stdout_fd,
+ int stderr_fd,
+ enum tst_cmd_flags flags);
+
+/* Executes tst_cmd_fds() and redirects its output to a file
+ * @stdout_path: path where to redirect stdout. Set NULL if redirection is
+ * not needed.
+ * @stderr_path: path where to redirect stderr. Set NULL if redirection is
+ * not needed.
+ * @flags: enum tst_cmd_flags
+ */
+int tst_cmd_(void (cleanup_fn)(void),
+ const char *const argv[],
+ const char *stdout_path,
+ const char *stderr_path,
+ enum tst_cmd_flags flags);
+
+#ifdef TST_TEST_H__
+static inline int tst_cmd_fds(const char *const argv[],
+ int stdout_fd,
+ int stderr_fd,
+ enum tst_cmd_flags flags)
+{
+ return tst_cmd_fds_(NULL, argv,
+ stdout_fd, stderr_fd, flags);
+}
+
+static inline int tst_cmd(const char *const argv[],
+ const char *stdout_path,
+ const char *stderr_path,
+ enum tst_cmd_flags flags)
+{
+ return tst_cmd_(NULL, argv,
+ stdout_path, stderr_path, flags);
+}
+#else
+static inline int tst_cmd_fds(void (cleanup_fn)(void),
+ const char *const argv[],
+ int stdout_fd,
+ int stderr_fd,
+ enum tst_cmd_flags flags)
+{
+ return tst_cmd_fds_(cleanup_fn, argv,
+ stdout_fd, stderr_fd, flags);
+}
+
+static inline int tst_cmd(void (cleanup_fn)(void),
+ const char *const argv[],
+ const char *stdout_path,
+ const char *stderr_path,
+ enum tst_cmd_flags flags)
+{
+ return tst_cmd_(cleanup_fn, argv,
+ stdout_path, stderr_path, flags);
+}
+#endif
+
+/* Wrapper function for system(3), ignorcing SIGCHLD signal.
+ * @command: the command to be run.
+ */
+int tst_system(const char *command);
+
+#endif /* TST_CMD_H__ */
diff --git a/src/kernel/tests/include/tst_common.h b/src/kernel/tests/include/tst_common.h
new file mode 100644
index 0000000..fd7a900
--- /dev/null
+++ b/src/kernel/tests/include/tst_common.h
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ * Copyright (c) 2013 Stanislav Kholmanskikh <stanislav.kholmanskikh@oracle.com>
+ * Copyright (c) 2010 Ngie Cooper <yaneurabeya@gmail.com>
+ * Copyright (c) 2008 Mike Frysinger <vapier@gmail.com>
+ */
+
+#ifndef TST_COMMON_H__
+#define TST_COMMON_H__
+
+#define LTP_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#define LTP_ATTRIBUTE_UNUSED __attribute__((unused))
+#define LTP_ATTRIBUTE_UNUSED_RESULT __attribute__((warn_unused_result))
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+/* Round x to the next multiple of a.
+ * a should be a power of 2.
+ */
+#define LTP_ALIGN(x, a) __LTP_ALIGN_MASK(x, (typeof(x))(a) - 1)
+#define __LTP_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
+/**
+ * TST_RETRY_FUNC() - Repeatedly retry a function with an increasing delay.
+ * @FUNC - The function which will be retried
+ * @ECHCK - Function/macro for validating @FUNC return value
+ *
+ * This macro will call @FUNC in a loop with a delay between retries.
+ * If ECHCK(ret) evaluates to non-zero, the loop ends. The delay between
+ * retries starts at one microsecond and is then doubled each iteration until
+ * it exceeds one second (the total time sleeping will be approximately one
+ * second as well). When the delay exceeds one second, the loop will end.
+ * The TST_RETRY_FUNC() macro returns the last value returned by @FUNC.
+ */
+#define TST_RETRY_FUNC(FUNC, ECHCK) \
+ TST_RETRY_FN_EXP_BACKOFF(FUNC, ECHCK, 1)
+
+#define TST_RETRY_FN_EXP_BACKOFF(FUNC, ECHCK, MAX_DELAY) \
+({ unsigned int tst_delay_, tst_max_delay_; \
+ typeof(FUNC) tst_ret_; \
+ tst_delay_ = 1; \
+ tst_max_delay_ = tst_multiply_timeout(MAX_DELAY * 1000000); \
+ for (;;) { \
+ errno = 0; \
+ tst_ret_ = FUNC; \
+ if (ECHCK(tst_ret_)) \
+ break; \
+ if (tst_delay_ < tst_max_delay_) { \
+ usleep(tst_delay_); \
+ tst_delay_ *= 2; \
+ } else { \
+ break; \
+ } \
+ } \
+ tst_ret_; \
+})
+
+/*
+ * Return value validation macros for TST_RETRY_FUNC():
+ * TST_RETVAL_EQ0() - Check that value is equal to zero
+ */
+#define TST_RETVAL_EQ0(x) (!(x))
+
+/*
+ * TST_RETVAL_NOTNULL() - Check that value is not equal to zero/NULL
+ */
+#define TST_RETVAL_NOTNULL(x) (!!(x))
+
+/*
+ * TST_RETVAL_GE0() - Check that value is greater than or equal to zero
+ */
+#define TST_RETVAL_GE0(x) ((x) >= 0)
+
+#define TST_BUILD_BUG_ON(condition) \
+ do { ((void)sizeof(char[1 - 2 * !!(condition)])); } while (0)
+
+#define TST_BRK_SUPPORTS_ONLY_TCONF_TBROK(condition) \
+ TST_BUILD_BUG_ON(condition)
+
+#define TST_RES_SUPPORTS_TCONF_TFAIL_TINFO_TPASS_TWARN(condition) \
+ TST_BUILD_BUG_ON(condition)
+
+#endif /* TST_COMMON_H__ */
diff --git a/src/kernel/tests/include/tst_coredump.h b/src/kernel/tests/include/tst_coredump.h
new file mode 100644
index 0000000..e1f8925
--- /dev/null
+++ b/src/kernel/tests/include/tst_coredump.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ */
+
+#ifndef TST_COREDUMP__
+#define TST_COREDUMP__
+
+/*
+ * If crash is expected, avoid dumping corefile.
+ * 1 is a special value, that disables core-to-pipe.
+ * At the same time it is small enough value for
+ * core-to-file, so it skips creating cores as well.
+ */
+void tst_no_corefile(int verbose);
+
+#endif /* TST_COREDUMP_H */
+
diff --git a/src/kernel/tests/include/tst_cpu.h b/src/kernel/tests/include/tst_cpu.h
new file mode 100644
index 0000000..c83a582
--- /dev/null
+++ b/src/kernel/tests/include/tst_cpu.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_CPU_H__
+#define TST_CPU_H__
+
+long tst_ncpus(void);
+long tst_ncpus_conf(void);
+long tst_ncpus_max(void);
+
+#define VIRT_ANY 0 /* catch-all argument for tst_is_virt() */
+#define VIRT_XEN 1 /* xen dom0/domU */
+#define VIRT_KVM 2 /* only default virtual CPU */
+#define VIRT_OTHER 0xffff /* unrecognized hypervisor */
+
+int tst_is_virt(int virt_type);
+
+#endif /* TST_CPU_H__ */
diff --git a/src/kernel/tests/include/tst_crypto.h b/src/kernel/tests/include/tst_crypto.h
new file mode 100644
index 0000000..ae406bd
--- /dev/null
+++ b/src/kernel/tests/include/tst_crypto.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+/**
+ * @file tst_crypto.h
+ *
+ * Library for interacting with kernel's crypto layer using the netlink
+ * interface.
+ */
+
+#ifndef TST_CRYPTO_H
+#define TST_CRYPTO_H
+
+#include "lapi/cryptouser.h"
+
+/**
+ * A reference to a crypto session and associated state.
+ *
+ * Holds state relevant to a netlink crypto connection. The seq_num is used
+ * to tag each message sent to the netlink layer and is automatically
+ * incremented by the tst_crypto_ functions. When the netlink layer sends a
+ * response (ack) it will use the sequences number from the request.
+ *
+ * Some functions, such as delete ALG, may return EBUSY in which case it is
+ * safe to retry them. The retries field allows you to set the number of
+ * times this should be done. If set to zero the operation will only be tried
+ * once. For operations which do not return EBUSY, the field is ignored.
+ *
+ * Use TST_CRYPTO_SESSION_INIT to statically initialize this struct with sane
+ * defaults.
+ */
+struct tst_crypto_session {
+ /** File descriptor for the netlink socket */
+ int fd;
+ /** A sequence number used to identify responses from the kernel. */
+ uint32_t seq_num;
+ /** Number of times some operations will be retried. */
+ uint32_t retries;
+};
+
+/**
+ * Default static definition of tst_crypto_session.
+ *
+ * @relates tst_crypto_session
+ */
+#define TST_CRYPTO_SESSION_INIT {\
+ .fd = 0, \
+ .seq_num = 0, \
+ .retries = 1000 \
+}
+
+/**
+ * Creates a crypto session.
+ *
+ * @relates tst_crypto_session
+ * @param ses Session structure to use, it can be uninitialized.
+ *
+ * If some necessary feature is missing then it will call tst_brk() with
+ * TCONF, for any other error it will use TBROK.
+ */
+void tst_crypto_open(struct tst_crypto_session *ses);
+
+/**
+ * Close a crypto session.
+ *
+ * @relates tst_crypto_session
+ * @param ses The session to close.
+ */
+void tst_crypto_close(struct tst_crypto_session *ses);
+
+/**
+ * Add a crypto algorithm to a session.
+ *
+ * @relates tst_crypto_session
+ * @param ses An open session.
+ * @param alg The crypto algorithm or module to add.
+ *
+ * This requests a new crypto algorithm/engine/module to be initialized by the
+ * kernel. It sends the request contained in alg and then waits for a
+ * response. If sending the message or receiving the ack fails at the netlink
+ * level then tst_brk() with TBROK will be called.
+ *
+ * @return On success it will return 0 otherwise it will return an inverted
+ * error code from the crypto layer.
+ */
+int tst_crypto_add_alg(struct tst_crypto_session *ses,
+ const struct crypto_user_alg *alg);
+
+/**
+ * Delete a crypto algorithm from a session.
+ *
+ * @relates tst_crypto_session
+ * @param ses An open session.
+ * @param alg The crypto algorithm to delete.
+ *
+ * Request that the kernel remove an existing crypto algorithm. This behaves
+ * in a similar way to tst_crypto_add_alg() except that it is the inverse
+ * operation and that it is not unusual for the crypto layer to return
+ * EBUSY. If EBUSY is returned then the function will internally retry the
+ * operation tst_crypto_session::retries times before giving up and returning
+ * EBUSY.
+ *
+ * Return: Either 0 or an inverted error code from the crypto layer. If called
+ * during cleanup it may return a positive ENODATA value from the LTP
+ * library, you don't need to log this error as it will already have
+ * been printed by tst_brk().
+ */
+int tst_crypto_del_alg(struct tst_crypto_session *ses,
+ const struct crypto_user_alg *alg);
+
+#endif /* TST_CRYPTO_H */
diff --git a/src/kernel/tests/include/tst_device.h b/src/kernel/tests/include/tst_device.h
new file mode 100644
index 0000000..00687a2
--- /dev/null
+++ b/src/kernel/tests/include/tst_device.h
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016-2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_DEVICE_H__
+#define TST_DEVICE_H__
+
+#include <unistd.h>
+
+struct tst_device {
+ const char *dev;
+ const char *fs_type;
+};
+
+/*
+ * Automatically initialized if test.needs_device is set.
+ */
+extern struct tst_device *tst_device;
+
+/*
+ * Just like umount() but retries several times on failure.
+ * @path: Path to umount
+ */
+int tst_umount(const char *path);
+
+/*
+ * Verifies if an earlier mount is successful or not.
+ * @path: Mount path to verify
+ */
+int tst_is_mounted(const char *path);
+int tst_is_mounted_at_tmpdir(const char *path);
+
+/*
+ * Clears a first few blocks of the device. This is needed when device has
+ * already been formatted with a filesystems, subset of mkfs.foo utils aborts
+ * the operation if it finds a filesystem signature there.
+ *
+ * Note that this is called from tst_mkfs() automatically, so you probably will
+ * not need to use this from the test yourself.
+ */
+int tst_clear_device(const char *dev);
+
+/*
+ * Finds a free xloop device for use and returns the free xloopdev minor(-1 for no
+ * free xloopdev). If path is non-NULL, it will be filled with free xloopdev path.
+ *
+ */
+int tst_find_free_xloopdev(const char *path, size_t path_len);
+
+/*
+ * Attaches a file to a xloop device.
+ *
+ * @dev_path Path to the xloop device e.g. /dev/xloop0
+ * @file_path Path to a file e.g. disk.img
+ * @return Zero on success, non-zero otherwise.
+ */
+int tst_attach_device(const char *dev_path, const char *file_path);
+
+/*
+ * Detaches a file from a xloop device fd.
+ *
+ * @dev_path Path to the xloop device e.g. /dev/xloop0
+ * @dev_fd a open fd for the xloop device
+ * @return Zero on succes, non-zero otherwise.
+ */
+int tst_detach_device_by_fd(const char *dev_path, int dev_fd);
+
+/*
+ * Detaches a file from a xloop device.
+ *
+ * @dev_path Path to the xloop device e.g. /dev/xloop0
+ * @return Zero on succes, non-zero otherwise.
+ *
+ * Internally this function opens the device and calls
+ * tst_detach_device_by_fd(). If you keep device file descriptor open you
+ * have to call the by_fd() variant since having the device open twice will
+ * prevent it from being detached.
+ */
+int tst_detach_device(const char *dev_path);
+
+/*
+ * To avoid FS deferred IO metadata/cache interference, so we do syncfs
+ * simply before the tst_dev_bytes_written invocation. For easy to use,
+ * we create this inline function tst_dev_sync.
+ */
+int tst_dev_sync(int fd);
+
+/*
+ * Reads test block device stat file and returns the bytes written since the
+ * last call of this function.
+ * @dev: test block device
+ */
+unsigned long tst_dev_bytes_written(const char *dev);
+
+/*
+ * Wipe the contents of given directory but keep the directory itself
+ */
+void tst_purge_dir(const char *path);
+
+/*
+ * Find the file or path belongs to which block dev
+ * @path Path to find the backing dev
+ * @dev The block dev
+ */
+void tst_find_backing_dev(const char *path, char *dev);
+
+#endif /* TST_DEVICE_H__ */
diff --git a/src/kernel/tests/include/tst_fs.h b/src/kernel/tests/include/tst_fs.h
new file mode 100644
index 0000000..fc03905
--- /dev/null
+++ b/src/kernel/tests/include/tst_fs.h
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_FS_H__
+#define TST_FS_H__
+
+/* man 2 statfs or kernel-source/include/linux/magic.h */
+#define TST_BTRFS_MAGIC 0x9123683E
+#define TST_NFS_MAGIC 0x6969
+#define TST_RAMFS_MAGIC 0x858458f6
+#define TST_TMPFS_MAGIC 0x01021994
+#define TST_V9FS_MAGIC 0x01021997
+#define TST_XFS_MAGIC 0x58465342
+#define TST_EXT2_OLD_MAGIC 0xEF51
+/* ext2, ext3, ext4 have the same magic number */
+#define TST_EXT234_MAGIC 0xEF53
+#define TST_MINIX_MAGIC 0x137F
+#define TST_MINIX_MAGIC2 0x138F
+#define TST_MINIX2_MAGIC 0x2468
+#define TST_MINIX2_MAGIC2 0x2478
+#define TST_MINIX3_MAGIC 0x4D5A
+#define TST_UDF_MAGIC 0x15013346
+#define TST_SYSV2_MAGIC 0x012FF7B6
+#define TST_SYSV4_MAGIC 0x012FF7B5
+#define TST_UFS_MAGIC 0x00011954
+#define TST_UFS2_MAGIC 0x19540119
+#define TST_F2FS_MAGIC 0xF2F52010
+#define TST_NILFS_MAGIC 0x3434
+#define TST_EXOFS_MAGIC 0x5DF5
+#define TST_OVERLAYFS_MAGIC 0x794c7630
+
+enum {
+ TST_BYTES = 1,
+ TST_KB = 1024,
+ TST_MB = 1048576,
+ TST_GB = 1073741824,
+};
+
+#define OVL_BASE_MNTPOINT "mntpoint"
+#define OVL_LOWER OVL_BASE_MNTPOINT"/lower"
+#define OVL_UPPER OVL_BASE_MNTPOINT"/upper"
+#define OVL_WORK OVL_BASE_MNTPOINT"/work"
+#define OVL_MNT OVL_BASE_MNTPOINT"/ovl"
+
+/*
+ * @path: path is the pathname of any file within the mounted file system
+ * @mult: mult should be TST_KB, TST_MB or TST_GB
+ * the required free space is calculated by @size * @mult
+ */
+int tst_fs_has_free_(void (*cleanup)(void), const char *path,
+ unsigned int size, unsigned int mult);
+
+/*
+ * Returns filesystem magick for a given path.
+ *
+ * The expected usage is:
+ *
+ * if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) {
+ * tst_brkm(TCONF, cleanup,
+ * "Test not supported on NFS filesystem");
+ * }
+ *
+ * Or:
+ *
+ * long type;
+ *
+ * swtich ((type = tst_fs_type(cleanup, "."))) {
+ * case TST_NFS_MAGIC:
+ * case TST_TMPFS_MAGIC:
+ * case TST_RAMFS_MAGIC:
+ * tst_brkm(TCONF, cleanup, "Test not supported on %s filesystem",
+ * tst_fs_type_name(type));
+ * break;
+ * }
+ */
+long tst_fs_type_(void (*cleanup)(void), const char *path);
+
+/*
+ * Returns filesystem name given magic.
+ */
+const char *tst_fs_type_name(long f_type);
+
+/*
+ * Try to get maximum number of hard links to a regular file inside the @dir.
+ *
+ * Note: This number depends on the filesystem @dir is on.
+ *
+ * The code uses link(2) to create hard links to a single file until it gets
+ * EMLINK or creates 65535 links.
+ *
+ * If limit is hit maximal number of hardlinks is returned and the the @dir is
+ * filled with hardlinks in format "testfile%i" where i belongs to [0, limit)
+ * interval.
+ *
+ * If no limit is hit (succed to create 65535 without error) or if link()
+ * failed with ENOSPC or EDQUOT zero is returned previously created files are
+ * removed.
+ */
+int tst_fs_fill_hardlinks_(void (*cleanup) (void), const char *dir);
+
+/*
+ * Try to get maximum number of subdirectories in directory.
+ *
+ * Note: This number depends on the filesystem @dir is on.
+ *
+ * The code uses mkdir(2) to create directories in @dir until it gets EMLINK
+ * or creates 65535 directories.
+ *
+ * If limit is hit the maximal number of subdirectories is returned and the
+ * @dir is filled with subdirectories in format "testdir%i" where i belongs to
+ * [0, limit - 2) interval (because each newly created dir has two links
+ * already the '.' and link from parent dir).
+ *
+ * If no limit is hit or mkdir() failed with ENOSPC or EDQUOT zero is returned
+ * previously created directories are removed.
+ *
+ */
+int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir);
+
+/*
+ * Checks if a given directory contains any entities,
+ * returns 1 if directory is empty, 0 otherwise
+ */
+int tst_dir_is_empty_(void (*cleanup)(void), const char *name, int verbose);
+
+/*
+ * Search $PATH for prog_name and fills buf with absolute path if found.
+ *
+ * Returns -1 on failure, either command was not found or buffer was too small.
+ */
+int tst_get_path(const char *prog_name, char *buf, size_t buf_len);
+
+/*
+ * Fill a file with specified pattern
+ * @fd: file descriptor
+ * @pattern: pattern
+ * @bs: block size
+ * @bcount: blocks count
+ */
+int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount);
+
+/*
+ * Preallocate space in open file. If fallocate() fails, falls back to
+ * using tst_fill_fd().
+ * @fd: file descriptor
+ * @bs: block size
+ * @bcount: blocks count
+ */
+int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount);
+
+/*
+ * Creates/ovewrites a file with specified pattern
+ * @path: path to file
+ * @pattern: pattern
+ * @bs: block size
+ * @bcount: blocks amount
+ */
+int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount);
+
+/*
+ * Creates file of specified size. Space will be only preallocated if possible.
+ * @path: path to file
+ * @bs: block size
+ * @bcount: blocks amount
+ */
+int tst_prealloc_file(const char *path, size_t bs, size_t bcount);
+
+#define TST_FS_SKIP_FUSE 0x01
+
+/*
+ * Return 1 if a specified fiilsystem is supported
+ * Return 0 if a specified fiilsystem isn't supported
+ */
+int tst_fs_is_supported(const char *fs_type, int flags);
+
+/*
+ * Returns NULL-terminated array of kernel-supported filesystems.
+ */
+const char **tst_get_supported_fs_types(int flags);
+
+/*
+ * Creates and writes to files on given path until write fails with ENOSPC
+ */
+void tst_fill_fs(const char *path, int verbose);
+
+/*
+ * test if FIBMAP ioctl is supported
+ */
+int tst_fibmap(const char *filename);
+
+#ifdef TST_TEST_H__
+static inline long tst_fs_type(const char *path)
+{
+ return tst_fs_type_(NULL, path);
+}
+
+static inline int tst_fs_has_free(const char *path, unsigned int size,
+ unsigned int mult)
+{
+ return tst_fs_has_free_(NULL, path, size, mult);
+}
+
+static inline int tst_fs_fill_hardlinks(const char *dir)
+{
+ return tst_fs_fill_hardlinks_(NULL, dir);
+}
+
+static inline int tst_fs_fill_subdirs(const char *dir)
+{
+ return tst_fs_fill_subdirs_(NULL, dir);
+}
+
+static inline int tst_dir_is_empty(const char *name, int verbose)
+{
+ return tst_dir_is_empty_(NULL, name, verbose);
+}
+#else
+static inline long tst_fs_type(void (*cleanup)(void), const char *path)
+{
+ return tst_fs_type_(cleanup, path);
+}
+
+static inline int tst_fs_has_free(void (*cleanup)(void), const char *path,
+ unsigned int size, unsigned int mult)
+{
+ return tst_fs_has_free_(cleanup, path, size, mult);
+}
+
+static inline int tst_fs_fill_hardlinks(void (*cleanup)(void), const char *dir)
+{
+ return tst_fs_fill_hardlinks_(cleanup, dir);
+}
+
+static inline int tst_fs_fill_subdirs(void (*cleanup)(void), const char *dir)
+{
+ return tst_fs_fill_subdirs_(cleanup, dir);
+}
+
+static inline int tst_dir_is_empty(void (*cleanup)(void), const char *name, int verbose)
+{
+ return tst_dir_is_empty_(cleanup, name, verbose);
+}
+#endif
+
+#endif /* TST_FS_H__ */
diff --git a/src/kernel/tests/include/tst_fuzzy_sync.h b/src/kernel/tests/include/tst_fuzzy_sync.h
new file mode 100644
index 0000000..4141f5c
--- /dev/null
+++ b/src/kernel/tests/include/tst_fuzzy_sync.h
@@ -0,0 +1,776 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2017-2018 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+/**
+ * @file tst_fuzzy_sync.h
+ * Fuzzy Synchronisation - abbreviated to fzsync
+ *
+ * This library is intended to help reproduce race conditions by synchronising
+ * two threads at a given place by marking the range a race may occur
+ * in. Because the exact place where any race occurs is within the kernel,
+ * and therefore impossible to mark accurately, the library may add randomised
+ * delays to either thread in order to help find the exact race timing.
+ *
+ * Currently only two way races are explicitly supported, that is races
+ * involving two threads or processes. We refer to the main test thread as
+ * thread A and the child thread as thread B.
+ *
+ * In each thread you need a simple while- or for-loop which the tst_fzsync_*
+ * functions are called in. In the simplest case thread A will look something
+ * like:
+ *
+ * tst_fzsync_pair_reset(&pair, run_thread_b);
+ * while (tst_fzsync_run_a(&pair)) {
+ * // Perform some setup which must happen before the race
+ * tst_fzsync_start_race_a(&pair);
+ * // Do some dodgy syscall
+ * tst_fzsync_end_race_a(&pair);
+ * }
+ *
+ * Then in thread B (run_thread_b):
+ *
+ * while (tst_fzsync_run_b(&pair)) {
+ * tst_fzsync_start_race_b(&pair);
+ * // Do something which can race with the dodgy syscall in A
+ * tst_fzsync_end_race_b(&pair)
+ * }
+ *
+ * The calls to tst_fzsync_start/end_race and tst_fzsync_run_a/b block (at
+ * least) until both threads have enter them. These functions can only be
+ * called once for each iteration, but further synchronisation points can be
+ * added by calling tst_fzsync_wait_a() and tst_fzsync_wait_b() in each
+ * thread.
+ *
+ * The execution of the loops in threads A and B are bounded by both iteration
+ * count and time. A slow machine is likely to be limited by time and a fast
+ * one by iteration count. The user can use the -i parameter to run the test
+ * multiple times or LTP_TIMEOUT_MUL to give the test more time.
+ *
+ * It is possible to use the library just for tst_fzsync_pair_wait() to get a
+ * basic spin wait. However if you are actually testing a race condition then
+ * it is recommended to use tst_fzsync_start_race_a/b even if the
+ * randomisation is not needed. It provides some semantic information which
+ * may be useful in the future.
+ *
+ * For a usage example see testcases/cve/cve-2016-7117.c or just run
+ * 'git grep tst_fuzzy_sync.h'
+ *
+ * @sa tst_fzsync_pair
+ */
+
+#include <sys/time.h>
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "tst_atomic.h"
+#include "tst_timer.h"
+#include "tst_safe_pthread.h"
+
+#ifndef TST_FUZZY_SYNC_H__
+#define TST_FUZZY_SYNC_H__
+
+/* how much of exec time is sampling allowed to take */
+#define SAMPLING_SLICE 0.5f
+
+/** Some statistics for a variable */
+struct tst_fzsync_stat {
+ float avg;
+ float avg_dev;
+ float dev_ratio;
+};
+
+/**
+ * The state of a two way synchronisation or race.
+ *
+ * This contains all the necessary state for approximately synchronising two
+ * sections of code in different threads.
+ *
+ * Some of the fields can be configured before calling
+ * tst_fzsync_pair_reset(), however this is mainly for debugging purposes. If
+ * a test requires one of the parameters to be modified, we should consider
+ * finding a way of automatically selecting an appropriate value at runtime.
+ *
+ * Internal fields should only be accessed by library functions.
+ */
+struct tst_fzsync_pair {
+ /**
+ * The rate at which old diff samples are forgotten
+ *
+ * Defaults to 0.25.
+ */
+ float avg_alpha;
+ /** Internal; Thread A start time */
+ struct timespec a_start;
+ /** Internal; Thread B start time */
+ struct timespec b_start;
+ /** Internal; Thread A end time */
+ struct timespec a_end;
+ /** Internal; Thread B end time */
+ struct timespec b_end;
+ /** Internal; Avg. difference between a_start and b_start */
+ struct tst_fzsync_stat diff_ss;
+ /** Internal; Avg. difference between a_start and a_end */
+ struct tst_fzsync_stat diff_sa;
+ /** Internal; Avg. difference between b_start and b_end */
+ struct tst_fzsync_stat diff_sb;
+ /** Internal; Avg. difference between a_end and b_end */
+ struct tst_fzsync_stat diff_ab;
+ /** Internal; Number of spins while waiting for the slower thread */
+ int spins;
+ struct tst_fzsync_stat spins_avg;
+ /**
+ * Internal; Number of spins to use in the delay.
+ *
+ * A negative value delays thread A and a positive delays thread B.
+ */
+ int delay;
+ int delay_bias;
+ /**
+ * Internal; The number of samples left or the sampling state.
+ *
+ * A positive value is the number of remaining mandatory
+ * samples. Zero or a negative indicate some other state.
+ */
+ int sampling;
+ /**
+ * The Minimum number of statistical samples which must be collected.
+ *
+ * The minimum number of iterations which must be performed before a
+ * random delay can be calculated. Defaults to 1024.
+ */
+ int min_samples;
+ /**
+ * The maximum allowed proportional average deviation.
+ *
+ * A value in the range (0, 1) which gives the maximum average
+ * deviation which must be attained before random delays can be
+ * calculated.
+ *
+ * It is a ratio of (average_deviation / total_time). The default is
+ * 0.1, so this allows an average deviation of at most 10%.
+ */
+ float max_dev_ratio;
+
+ /** Internal; Atomic counter used by fzsync_pair_wait() */
+ int a_cntr;
+ /** Internal; Atomic counter used by fzsync_pair_wait() */
+ int b_cntr;
+ /** Internal; Used by tst_fzsync_pair_exit() and fzsync_pair_wait() */
+ int exit;
+ /**
+ * The maximum desired execution time as a proportion of the timeout
+ *
+ * A value x so that 0 < x < 1 which decides how long the test should
+ * be run for (assuming the loop limit is not exceeded first).
+ *
+ * Defaults to 0.5 (~150 seconds with default timeout).
+ */
+ float exec_time_p;
+ /** Internal; The test time remaining on tst_fzsync_pair_reset() */
+ float exec_time_start;
+ /**
+ * The maximum number of iterations to execute during the test
+ *
+ * Defaults to a large number, but not too large.
+ */
+ int exec_loops;
+ /** Internal; The current loop index */
+ int exec_loop;
+ /** Internal; The second thread or 0 */
+ pthread_t thread_b;
+};
+
+#define CHK(param, low, hi, def) do { \
+ pair->param = (pair->param ? pair->param : def); \
+ if (pair->param < low) \
+ tst_brk(TBROK, #param " is less than the lower bound " #low); \
+ if (pair->param > hi) \
+ tst_brk(TBROK, #param " is more than the upper bound " #hi); \
+ } while (0)
+/**
+ * Ensures that any Fuzzy Sync parameters are properly set
+ *
+ * @relates tst_fzsync_pair
+ *
+ * Usually called from the setup function, it sets default parameter values or
+ * validates any existing non-defaults.
+ *
+ * @sa tst_fzsync_pair_reset()
+ */
+static void tst_fzsync_pair_init(struct tst_fzsync_pair *pair)
+{
+ CHK(avg_alpha, 0, 1, 0.25);
+ CHK(min_samples, 20, INT_MAX, 1024);
+ CHK(max_dev_ratio, 0, 1, 0.1);
+ CHK(exec_time_p, 0, 1, 0.5);
+ CHK(exec_loops, 20, INT_MAX, 3000000);
+}
+#undef CHK
+
+/**
+ * Exit and join thread B if necessary.
+ *
+ * @relates tst_fzsync_pair
+ *
+ * Call this from your cleanup function.
+ */
+static void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair)
+{
+ if (pair->thread_b) {
+ /* Revoke thread B if parent hits accidental break */
+ if (!pair->exit) {
+ tst_atomic_store(1, &pair->exit);
+ usleep(100000);
+ pthread_cancel(pair->thread_b);
+ }
+ SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
+ pair->thread_b = 0;
+ }
+}
+
+/** To store the run_b pointer and pass to tst_fzsync_thread_wrapper */
+struct tst_fzsync_run_thread {
+ void *(*func)(void *);
+ void *arg;
+};
+
+/**
+ * Wrap run_b for tst_fzsync_pair_reset to enable pthread cancel
+ * at the start of the thread B.
+ */
+static void *tst_fzsync_thread_wrapper(void *run_thread)
+{
+ struct tst_fzsync_run_thread t = *(struct tst_fzsync_run_thread *)run_thread;
+
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ return t.func(t.arg);
+}
+
+/**
+ * Zero some stat fields
+ *
+ * @relates tst_fzsync_stat
+ */
+static void tst_init_stat(struct tst_fzsync_stat *s)
+{
+ s->avg = 0;
+ s->avg_dev = 0;
+}
+
+/**
+ * Reset or initialise fzsync.
+ *
+ * @relates tst_fzsync_pair
+ * @param pair The state structure initialised with TST_FZSYNC_PAIR_INIT.
+ * @param run_b The function defining thread B or NULL.
+ *
+ * Call this from your main test function (thread A), just before entering the
+ * main loop. It will (re)set any variables needed by fzsync and (re)start
+ * thread B using the function provided.
+ *
+ * If you need to use fork or clone to start the second thread/process then
+ * you can pass NULL to run_b and handle starting and stopping thread B
+ * yourself. You may need to place tst_fzsync_pair in some shared memory as
+ * well.
+ *
+ * @sa tst_fzsync_pair_init()
+ */
+static void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair,
+ void *(*run_b)(void *))
+{
+ tst_fzsync_pair_cleanup(pair);
+
+ tst_init_stat(&pair->diff_ss);
+ tst_init_stat(&pair->diff_sa);
+ tst_init_stat(&pair->diff_sb);
+ tst_init_stat(&pair->diff_ab);
+ tst_init_stat(&pair->spins_avg);
+ pair->delay = 0;
+ pair->sampling = pair->min_samples;
+
+ pair->exec_loop = 0;
+
+ pair->a_cntr = 0;
+ pair->b_cntr = 0;
+ pair->exit = 0;
+ if (run_b) {
+ static struct tst_fzsync_run_thread wrap_run_b;
+
+ wrap_run_b.func = run_b;
+ wrap_run_b.arg = NULL;
+ SAFE_PTHREAD_CREATE(&pair->thread_b, 0, tst_fzsync_thread_wrapper, &wrap_run_b);
+ }
+
+ pair->exec_time_start = (float)tst_timeout_remaining();
+}
+
+/**
+ * Print stat
+ *
+ * @relates tst_fzsync_stat
+ */
+static inline void tst_fzsync_stat_info(struct tst_fzsync_stat stat,
+ char *unit, char *name)
+{
+ tst_res(TINFO,
+ "%1$-17s: { avg = %3$5.0f%2$s, avg_dev = %4$5.0f%2$s, dev_ratio = %5$.2f }",
+ name, unit, stat.avg, stat.avg_dev, stat.dev_ratio);
+}
+
+/**
+ * Print some synchronisation statistics
+ *
+ * @relates tst_fzsync_pair
+ */
+static void tst_fzsync_pair_info(struct tst_fzsync_pair *pair)
+{
+ tst_res(TINFO, "loop = %d, delay_bias = %d",
+ pair->exec_loop, pair->delay_bias);
+ tst_fzsync_stat_info(pair->diff_ss, "ns", "start_a - start_b");
+ tst_fzsync_stat_info(pair->diff_sa, "ns", "end_a - start_a");
+ tst_fzsync_stat_info(pair->diff_sb, "ns", "end_b - start_b");
+ tst_fzsync_stat_info(pair->diff_ab, "ns", "end_a - end_b");
+ tst_fzsync_stat_info(pair->spins_avg, " ", "spins");
+}
+
+/** Wraps clock_gettime */
+static inline void tst_fzsync_time(struct timespec *t)
+{
+#ifdef CLOCK_MONOTONIC_RAW
+ clock_gettime(CLOCK_MONOTONIC_RAW, t);
+#else
+ clock_gettime(CLOCK_MONOTONIC, t);
+#endif
+}
+
+/**
+ * Exponential moving average
+ *
+ * @param alpha The preference for recent samples over old ones.
+ * @param sample The current sample
+ * @param prev_avg The average of the all the previous samples
+ *
+ * @return The average including the current sample.
+ */
+static inline float tst_exp_moving_avg(float alpha,
+ float sample,
+ float prev_avg)
+{
+ return alpha * sample + (1.0 - alpha) * prev_avg;
+}
+
+/**
+ * Update a stat with a new sample
+ *
+ * @relates tst_fzsync_stat
+ */
+static inline void tst_upd_stat(struct tst_fzsync_stat *s,
+ float alpha,
+ float sample)
+{
+ s->avg = tst_exp_moving_avg(alpha, sample, s->avg);
+ s->avg_dev = tst_exp_moving_avg(alpha,
+ fabs(s->avg - sample), s->avg_dev);
+ s->dev_ratio = fabs(s->avg ? s->avg_dev / s->avg : 0);
+}
+
+/**
+ * Update a stat with a new diff sample
+ *
+ * @relates tst_fzsync_stat
+ */
+static inline void tst_upd_diff_stat(struct tst_fzsync_stat *s,
+ float alpha,
+ struct timespec t1,
+ struct timespec t2)
+{
+ tst_upd_stat(s, alpha, tst_timespec_diff_ns(t1, t2));
+}
+
+/**
+ * Calculate various statistics and the delay
+ *
+ * This function helps create the fuzz in fuzzy sync. Imagine we have the
+ * following timelines in threads A and B:
+ *
+ * start_race_a
+ * ^ end_race_a (a)
+ * | ^
+ * | |
+ * - --+------------------------+-- - -
+ * | Syscall A | Thread A
+ * - --+------------------------+-- - -
+ * - --+----------------+-------+-- - -
+ * | Syscall B | spin | Thread B
+ * - --+----------------+-------+-- - -
+ * | |
+ * ^ ^
+ * start_race_b end_race_b
+ *
+ * Here we have synchronised the calls to syscall A and B with start_race_{a,
+ * b} so that they happen at approximately the same time in threads A and
+ * B. If the race condition occurs during the entry code for these two
+ * functions then we will quickly hit it. If it occurs during the exit code of
+ * B and mid way through A, then we will quickly hit it.
+ *
+ * However if the exit paths of A and B need to be aligned and (end_race_a -
+ * end_race_b) is large relative to the variation in call times, the
+ * probability of hitting the race condition is close to zero. To solve this
+ * scenario (and others) a randomised delay is introduced before the syscalls
+ * in A and B. Given enough time the following should happen where the exit
+ * paths are now synchronised:
+ *
+ * start_race_a
+ * ^ end_race_a (a)
+ * | ^
+ * | |
+ * - --+------------------------+-- - -
+ * | Syscall A | Thread A
+ * - --+------------------------+-- - -
+ * - --+-------+----------------+-- - -
+ * | delay | Syscall B | Thread B
+ * - --+-------+----------------+-- - -
+ * | |
+ * ^ ^
+ * start_race_b end_race_b
+ *
+ * The delay is not introduced immediately and the delay range is only
+ * calculated once the average relative deviation has dropped below some
+ * percentage of the total time.
+ *
+ * The delay range is chosen so that any point in Syscall A could be
+ * synchronised with any point in Syscall B using a value from the
+ * range. Because the delay range may be too large for a linear search, we use
+ * an evenly distributed random function to pick a value from it.
+ *
+ * The delay range goes from positive to negative. A negative delay will delay
+ * thread A and a positive one will delay thread B. The range is bounded by
+ * the point where the entry code to Syscall A is synchronised with the exit
+ * to Syscall B and the entry code to Syscall B is synchronised with the exit
+ * of A.
+ *
+ * In order to calculate the lower bound (the max delay of A) we can simply
+ * negate the execution time of Syscall B and convert it to a spin count. For
+ * the upper bound (the max delay of B), we just take the execution time of A
+ * and convert it to a spin count.
+ *
+ * In order to calculate spin count we need to know approximately how long a
+ * spin takes and divide the delay time with it. We find this by first
+ * counting how many spins one thread spends waiting for the other during
+ * end_race[1]. We also know when each syscall exits so we can take the
+ * difference between the exit times and divide it with the number of spins
+ * spent waiting.
+ *
+ * All the times and counts we use in the calculation are averaged over a
+ * variable number of iterations. There is an initial sampling period where we
+ * simply collect time and count samples then calculate their averages. When a
+ * minimum number of samples have been collected, and if the average deviation
+ * is below some proportion of the average sample magnitude, then the sampling
+ * period is ended. On all further iterations a random delay is calculated and
+ * applied, but the averages are not updated.
+ *
+ * [1] This assumes there is always a significant difference. The algorithm
+ * may fail to introduce a delay (when one is needed) in situations where
+ * Syscall A and B finish at approximately the same time.
+ *
+ * @relates tst_fzsync_pair
+ */
+static void tst_fzsync_pair_update(struct tst_fzsync_pair *pair)
+{
+ float alpha = pair->avg_alpha;
+ float per_spin_time, time_delay;
+ float max_dev = pair->max_dev_ratio;
+ int over_max_dev;
+
+ pair->delay = pair->delay_bias;
+
+ over_max_dev = pair->diff_ss.dev_ratio > max_dev
+ || pair->diff_sa.dev_ratio > max_dev
+ || pair->diff_sb.dev_ratio > max_dev
+ || pair->diff_ab.dev_ratio > max_dev
+ || pair->spins_avg.dev_ratio > max_dev;
+
+ if (pair->sampling > 0 || over_max_dev) {
+ tst_upd_diff_stat(&pair->diff_ss, alpha,
+ pair->a_start, pair->b_start);
+ tst_upd_diff_stat(&pair->diff_sa, alpha,
+ pair->a_end, pair->a_start);
+ tst_upd_diff_stat(&pair->diff_sb, alpha,
+ pair->b_end, pair->b_start);
+ tst_upd_diff_stat(&pair->diff_ab, alpha,
+ pair->a_end, pair->b_end);
+ tst_upd_stat(&pair->spins_avg, alpha, pair->spins);
+ if (pair->sampling > 0 && --pair->sampling == 0) {
+ tst_res(TINFO, "Minimum sampling period ended");
+ tst_fzsync_pair_info(pair);
+ }
+ } else if (fabsf(pair->diff_ab.avg) >= 1) {
+ per_spin_time = fabsf(pair->diff_ab.avg) / MAX(pair->spins_avg.avg, 1.0f);
+ time_delay = drand48() * (pair->diff_sa.avg + pair->diff_sb.avg)
+ - pair->diff_sb.avg;
+ pair->delay += (int)(1.1 * time_delay / per_spin_time);
+
+ if (!pair->sampling) {
+ tst_res(TINFO,
+ "Reached deviation ratios < %.2f, introducing randomness",
+ pair->max_dev_ratio);
+ tst_res(TINFO, "Delay range is [-%d, %d]",
+ (int)(pair->diff_sb.avg / per_spin_time) + pair->delay_bias,
+ (int)(pair->diff_sa.avg / per_spin_time) - pair->delay_bias);
+ tst_fzsync_pair_info(pair);
+ pair->sampling = -1;
+ }
+ } else if (!pair->sampling) {
+ tst_res(TWARN, "Can't calculate random delay");
+ tst_fzsync_pair_info(pair);
+ pair->sampling = -1;
+ }
+
+ pair->spins = 0;
+}
+
+/**
+ * Wait for the other thread
+ *
+ * @relates tst_fzsync_pair
+ * @param our_cntr The counter for the thread we are on
+ * @param other_cntr The counter for the thread we are synchronising with
+ * @param spins A pointer to the spin counter or NULL
+ *
+ * Used by tst_fzsync_pair_wait_a(), tst_fzsync_pair_wait_b(),
+ * tst_fzsync_start_race_a(), etc. If the calling thread is ahead of the other
+ * thread, then it will spin wait. Unlike pthread_barrier_wait it will never
+ * use futex and can count the number of spins spent waiting.
+ *
+ * @return A non-zero value if the thread should continue otherwise the
+ * calling thread should exit.
+ */
+static inline void tst_fzsync_pair_wait(int *our_cntr,
+ int *other_cntr,
+ int *spins)
+{
+ if (tst_atomic_inc(other_cntr) == INT_MAX) {
+ /*
+ * We are about to break the invariant that the thread with
+ * the lowest count is in front of the other. So we must wait
+ * here to ensure the other thread has at least reached the
+ * line above before doing that. If we are in rear position
+ * then our counter may already have been set to zero.
+ */
+ while (tst_atomic_load(our_cntr) > 0
+ && tst_atomic_load(our_cntr) < INT_MAX) {
+ if (spins)
+ (*spins)++;
+ }
+
+ tst_atomic_store(0, other_cntr);
+ /*
+ * Once both counters have been set to zero the invariant
+ * is restored and we can continue.
+ */
+ while (tst_atomic_load(our_cntr) > 1)
+ ;
+ } else {
+ /*
+ * If our counter is less than the other thread's we are ahead
+ * of it and need to wait.
+ */
+ while (tst_atomic_load(our_cntr) < tst_atomic_load(other_cntr)) {
+ if (spins)
+ (*spins)++;
+ }
+ }
+}
+
+/**
+ * Wait in thread A
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_pair_wait
+ */
+static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair)
+{
+ tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, NULL);
+}
+
+/**
+ * Wait in thread B
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_pair_wait
+ */
+static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair)
+{
+ tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, NULL);
+}
+
+/**
+ * Decide whether to continue running thread A
+ *
+ * @relates tst_fzsync_pair
+ *
+ * Checks some values and decides whether it is time to break the loop of
+ * thread A.
+ *
+ * @return True to continue and false to break.
+ * @sa tst_fzsync_run_a
+ */
+static inline int tst_fzsync_run_a(struct tst_fzsync_pair *pair)
+{
+ int exit = 0;
+ float rem_p = 1 - tst_timeout_remaining() / pair->exec_time_start;
+
+ if ((pair->exec_time_p * SAMPLING_SLICE < rem_p)
+ && (pair->sampling > 0)) {
+ tst_res(TINFO, "Stopped sampling at %d (out of %d) samples, "
+ "sampling time reached 50%% of the total time limit",
+ pair->exec_loop, pair->min_samples);
+ pair->sampling = 0;
+ tst_fzsync_pair_info(pair);
+ }
+
+ if (pair->exec_time_p < rem_p) {
+ tst_res(TINFO,
+ "Exceeded execution time, requesting exit");
+ exit = 1;
+ }
+
+ if (++pair->exec_loop > pair->exec_loops) {
+ tst_res(TINFO,
+ "Exceeded execution loops, requesting exit");
+ exit = 1;
+ }
+
+ tst_atomic_store(exit, &pair->exit);
+ tst_fzsync_wait_a(pair);
+
+ if (exit) {
+ tst_fzsync_pair_cleanup(pair);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Decide whether to continue running thread B
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_run_a
+ */
+static inline int tst_fzsync_run_b(struct tst_fzsync_pair *pair)
+{
+ tst_fzsync_wait_b(pair);
+ return !tst_atomic_load(&pair->exit);
+}
+
+/**
+ * Marks the start of a race region in thread A
+ *
+ * @relates tst_fzsync_pair
+ *
+ * This should be placed just before performing whatever action can cause a
+ * race condition. Usually it is placed just before a syscall and
+ * tst_fzsync_end_race_a() is placed just afterwards.
+ *
+ * A corresponding call to tst_fzsync_start_race_b() should be made in thread
+ * B.
+ *
+ * @return A non-zero value if the calling thread should continue to loop. If
+ * it returns zero then tst_fzsync_exit() has been called and you must exit
+ * the thread.
+ *
+ * @sa tst_fzsync_pair_update
+ */
+static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair)
+{
+ volatile int delay;
+
+ tst_fzsync_pair_update(pair);
+
+ tst_fzsync_wait_a(pair);
+
+ delay = pair->delay;
+ while (delay < 0)
+ delay++;
+
+ tst_fzsync_time(&pair->a_start);
+}
+
+/**
+ * Marks the end of a race region in thread A
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_start_race_a
+ */
+static inline void tst_fzsync_end_race_a(struct tst_fzsync_pair *pair)
+{
+ tst_fzsync_time(&pair->a_end);
+ tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, &pair->spins);
+}
+
+/**
+ * Marks the start of a race region in thread B
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_start_race_a
+ */
+static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair)
+{
+ volatile int delay;
+
+ tst_fzsync_wait_b(pair);
+
+ delay = pair->delay;
+ while (delay > 0)
+ delay--;
+
+ tst_fzsync_time(&pair->b_start);
+}
+
+/**
+ * Marks the end of a race region in thread B
+ *
+ * @relates tst_fzsync_pair
+ * @sa tst_fzsync_start_race_a
+ */
+static inline void tst_fzsync_end_race_b(struct tst_fzsync_pair *pair)
+{
+ tst_fzsync_time(&pair->b_end);
+ tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, &pair->spins);
+}
+
+/**
+ * Add some amount to the delay bias
+ *
+ * @relates tst_fzsync_pair
+ * @param change The amount to add, can be negative
+ *
+ * A positive change delays thread B and a negative one delays thread
+ * A.
+ *
+ * It is intended to be used in tests where the time taken by syscall A and/or
+ * B are significantly affected by their chronological order. To the extent
+ * that the delay range will not include the correct values if too many of the
+ * initial samples are taken when the syscalls (or operations within the
+ * syscalls) happen in the wrong order.
+ *
+ * An example of this is cve/cve-2016-7117.c where a call to close() is racing
+ * with a call to recvmmsg(). If close() happens before recvmmsg() has chance
+ * to check if the file descriptor is open then recvmmsg() completes very
+ * quickly. If the call to close() happens once recvmmsg() has already checked
+ * the descriptor it takes much longer. The sample where recvmmsg() completes
+ * quickly is essentially invalid for our purposes. The test uses the simple
+ * heuristic of whether recvmmsg() returns EBADF, to decide if it should call
+ * tst_fzsync_pair_add_bias() to further delay syscall B.
+ */
+static inline void tst_fzsync_pair_add_bias(struct tst_fzsync_pair *pair, int change)
+{
+ if (pair->sampling > 0)
+ pair->delay_bias += change;
+}
+
+#endif /* TST_FUZZY_SYNC_H__ */
diff --git a/src/kernel/tests/include/tst_get_bad_addr.h b/src/kernel/tests/include/tst_get_bad_addr.h
new file mode 100644
index 0000000..69d7402
--- /dev/null
+++ b/src/kernel/tests/include/tst_get_bad_addr.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef TST_GET_BAD_ADDR_H__
+#define TST_GET_BAD_ADDR_H__
+
+/* Functions from lib/tst_get_bad_addr.c */
+void *tst_get_bad_addr(void (*cleanup_fn) (void));
+
+#endif /* TST_GET_BAD_ADDR_H__ */
diff --git a/src/kernel/tests/include/tst_hugepage.h b/src/kernel/tests/include/tst_hugepage.h
new file mode 100644
index 0000000..e08a2da
--- /dev/null
+++ b/src/kernel/tests/include/tst_hugepage.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ */
+
+#ifndef TST_HUGEPAGE__
+#define TST_HUGEPAGE__
+
+#define PATH_HUGEPAGES "/sys/kernel/mm/hugepages/"
+#define PATH_NR_HPAGES "/proc/sys/vm/nr_hugepages"
+
+extern char *nr_opt; /* -s num Set the number of the been allocated hugepages */
+extern char *Hopt; /* -H /.. Location of hugetlbfs, i.e. -H /var/hugetlbfs */
+
+/*
+ * Get the default hugepage size. Returns 0 if hugepages are not supported.
+ */
+size_t tst_get_hugepage_size(void);
+
+/*
+ * Try the best to request a specified number of huge pages from system,
+ * it will store the reserved hpage number in tst_hugepages.
+ *
+ * Note: this depend on the status of system memory fragmentation.
+ */
+unsigned long tst_request_hugepages(unsigned long hpages);
+
+/*
+ * This variable is used for recording the number of hugepages which system can
+ * provides. It will be equal to 'hpages' if tst_request_hugepages on success,
+ * otherwise set it to a number of hugepages that we were able to reserve.
+ *
+ * If system does not support hugetlb, then it will be set to 0.
+ */
+extern unsigned long tst_hugepages;
+
+#endif /* TST_HUGEPAGE_H */
diff --git a/src/kernel/tests/include/tst_kconfig.h b/src/kernel/tests/include/tst_kconfig.h
new file mode 100644
index 0000000..2d2cfd7
--- /dev/null
+++ b/src/kernel/tests/include/tst_kconfig.h
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_KCONFIG_H__
+#define TST_KCONFIG_H__
+
+struct tst_kconfig_res {
+ char match;
+ char *value;
+};
+
+/**
+ * Reads a kernel config and parses it for values defined in kconfigs array.
+ *
+ * The path to the kernel config should be autodetected in most of the cases as
+ * the code looks for know locations. It can be explicitely set/overrided with
+ * the KCONFIG_PATH environment variable as well.
+ *
+ * The kcofings array is expected to contain strings in a format "CONFIG_FOO"
+ * or "CONFIG_FOO=bar". The result array has to be suitably sized to fit the
+ * results.
+ *
+ * @param kconfigs array of config strings to look for
+ * @param results array to store results to
+ * @param cnt size of the arrays
+ *
+ * The match in the tst_kconfig_res structure is set as follows:
+ *
+ * 'm' - config option set to m
+ * 'y' - config option set to y
+ * 'v' - config option set to other value
+ * 'n' - config option is not set
+ * 0 - config option not found
+ *
+ * In the case that match is set to 'v' the value points to a newly allocated
+ * string that holds the value.
+ */
+void tst_kconfig_read(const char *const kconfigs[],
+ struct tst_kconfig_res results[], size_t cnt);
+
+/**
+ * Checks if required kernel configuration options are set in the kernel
+ * config and exits the test with TCONF if at least one is missing.
+ *
+ * The config options can be passed in two different formats, either
+ * "CONFIG_FOO" in which case the option has to be set in order to continue the
+ * test or with an explicit value "CONFIG_FOO=bar" in which case the value has
+ * to match.
+ *
+ * @param kconfigs NULL-terminated array of config strings needed for the testrun.
+ */
+void tst_kconfig_check(const char *const kconfigs[]);
+
+#endif /* TST_KCONFIG_H__ */
diff --git a/src/kernel/tests/include/tst_kernel.h b/src/kernel/tests/include/tst_kernel.h
new file mode 100644
index 0000000..71ab946
--- /dev/null
+++ b/src/kernel/tests/include/tst_kernel.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_KERNEL_H__
+#define TST_KERNEL_H__
+
+/*
+ * Returns 32 if we are running on 32bit kernel and 64 if on 64bit kernel.
+ */
+int tst_kernel_bits(void);
+
+/**
+ * Checks support for the kernel driver.
+ *
+ * @param name The name of the driver.
+ * @return Returns 0 if the kernel has the driver or modprobe is missing.
+ */
+int tst_check_driver(const char *name);
+
+#endif /* TST_KERNEL_H__ */
diff --git a/src/kernel/tests/include/tst_kvercmp.h b/src/kernel/tests/include/tst_kvercmp.h
new file mode 100644
index 0000000..495e8db
--- /dev/null
+++ b/src/kernel/tests/include/tst_kvercmp.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2009-2016 Cyril Hrubis chrubis@suse.cz
+ */
+
+#ifndef TST_KVERCMP_H__
+#define TST_KVERCMP_H__
+
+/*
+ * The same as tst_kvercmp() but running kernel version is passed as parameter
+ * instead of utilizing uname().
+ */
+int tst_kvcmp(const char *cur_kver, int r1, int r2, int r3);
+
+/*
+ * Parsers string into three integer version.
+ */
+int tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3);
+
+/*
+ * Returns distribution name parsed from kernel version string or NULL.
+ */
+const char *tst_kvcmp_distname(const char *cur_kver);
+
+/*
+ * Compares versions up to five version numbers long.
+ */
+int tst_kvexcmp(const char *tst_exv, const char *cur_kver);
+
+/*
+ * Compare given kernel version with currently running kernel.
+ *
+ * Returns negative if older, 0 if the same and possitive if newer.
+ */
+int tst_kvercmp(int r1, int r2, int r3);
+
+struct tst_kern_exv {
+ char *dist_name;
+ char *extra_ver;
+};
+
+int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers);
+
+#endif /* TST_KVERCMP_H__ */
diff --git a/src/kernel/tests/include/tst_lockdown.h b/src/kernel/tests/include/tst_lockdown.h
new file mode 100644
index 0000000..78eaecc
--- /dev/null
+++ b/src/kernel/tests/include/tst_lockdown.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef TST_LOCKDOWN_H
+#define TST_LOCKDOWN_H
+
+#define PATH_LOCKDOWN "/sys/kernel/security/lockdown"
+
+int tst_lockdown_enabled(void);
+
+#endif /* TST_LOCKDOWN_H */
diff --git a/src/kernel/tests/include/tst_memutils.h b/src/kernel/tests/include/tst_memutils.h
new file mode 100644
index 0000000..91dad07
--- /dev/null
+++ b/src/kernel/tests/include/tst_memutils.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
+ */
+
+#ifndef TST_MEMUTILS_H__
+#define TST_MEMUTILS_H__
+
+/*
+ * Fill up to maxsize physical memory with fillchar, then free it for reuse.
+ * If maxsize is zero, fill as much memory as possible. This function is
+ * intended for data disclosure vulnerability tests to reduce the probability
+ * that a vulnerable kernel will leak a block of memory that was full of
+ * zeroes by chance.
+ *
+ * The function keeps a safety margin to avoid invoking OOM killer and
+ * respects the limitations of available address space. (Less than 3GB can be
+ * polluted on a 32bit system regardless of available physical RAM.)
+ */
+void tst_pollute_memory(size_t maxsize, int fillchar);
+
+#endif /* TST_MEMUTILS_H__ */
diff --git a/src/kernel/tests/include/tst_minmax.h b/src/kernel/tests/include/tst_minmax.h
new file mode 100644
index 0000000..6417dd7
--- /dev/null
+++ b/src/kernel/tests/include/tst_minmax.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_MINMAX_H__
+#define TST_MINMAX_H__
+
+#ifndef MIN
+# define MIN(a, b) ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+})
+#endif /* MIN */
+
+#ifndef MAX
+# define MAX(a, b) ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a > _b ? _a : _b; \
+})
+#endif /* MAX */
+
+#endif /* TST_MINMAX_H__ */
diff --git a/src/kernel/tests/include/tst_mkfs.h b/src/kernel/tests/include/tst_mkfs.h
new file mode 100644
index 0000000..b89bf81
--- /dev/null
+++ b/src/kernel/tests/include/tst_mkfs.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_MKFS_H__
+#define TST_MKFS_H__
+
+/*
+ * @dev: path to a device
+ * @fs_type: filesystem type
+ * @fs_opts: NULL or NULL terminated array of extra mkfs options
+ * @extra_opts: NULL or NULL terminated array of extra mkfs options
+ */
+void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *dev, const char *fs_type,
+ const char *const fs_opts[], const char *const extra_opts[]);
+
+#define SAFE_MKFS(device, fs_type, fs_opts, extra_opts) \
+ tst_mkfs_(__FILE__, __LINE__, NULL, device, fs_type, \
+ fs_opts, extra_opts)
+
+#endif /* TST_MKFS_H__ */
diff --git a/src/kernel/tests/include/tst_net.h b/src/kernel/tests/include/tst_net.h
new file mode 100644
index 0000000..daefdd9
--- /dev/null
+++ b/src/kernel/tests/include/tst_net.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2019 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef TST_NET_H_
+#define TST_NET_H_
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/types.h>
+
+void tst_get_in_addr(const char *ip_str, struct in_addr *ip);
+void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6);
+
+/*
+ * Find valid connection address for a given bound socket
+ */
+socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr);
+
+/*
+ * Initialize AF_INET/AF_INET6 socket address structure with address and port
+ */
+void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, uint16_t port);
+void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, uint16_t port);
+void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, uint16_t port);
+void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct in6_addr *ip_val, uint16_t port);
+
+void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr,
+ const char *port, const struct addrinfo *hints,
+ struct addrinfo **addr_info);
+
+#endif /* TST_NET_H_ */
diff --git a/src/kernel/tests/include/tst_netlink.h b/src/kernel/tests/include/tst_netlink.h
new file mode 100644
index 0000000..2030ac3
--- /dev/null
+++ b/src/kernel/tests/include/tst_netlink.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+/**
+ * @file tst_netlink.h
+ *
+ * Library for communicating with the kernel over the netlink interface.
+ */
+
+#ifndef TST_NETLINK_H
+#define TST_NETLINK_H
+
+#include <linux/netlink.h>
+
+#ifndef NETLINK_CRYPTO
+/**
+ * The netlink-crypto socket protocol.
+ */
+#define NETLINK_CRYPTO 21
+#endif
+
+/** @private */
+static inline ssize_t safe_netlink_send(const char *file, const int lineno,
+ int fd, const struct nlmsghdr *nh,
+ const void *payload)
+{
+ struct sockaddr_nl sa = { .nl_family = AF_NETLINK };
+ struct iovec iov[2] = {
+ {(struct nlmsghdr *)nh, sizeof(*nh)},
+ {(void *)payload, nh->nlmsg_len - sizeof(*nh)}
+ };
+ struct msghdr msg = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = iov,
+ .msg_iovlen = 2
+ };
+
+ return safe_sendmsg(file, lineno, nh->nlmsg_len, fd, &msg, 0);
+}
+
+/**
+ * Sends a netlink message using safe_sendmsg().
+ *
+ * @param fd netlink socket file descriptor.
+ * @param nl_header netlink header structure describing the message.
+ * @param payload an opaque object containing the message data.
+ *
+ * You should set the message length, type and flags to appropriate values
+ * within the nl_header object. See lib/tst_crypto.c for an example.
+ *
+ * @return The number of bytes sent.
+ */
+#define SAFE_NETLINK_SEND(fd, nl_header, payload) \
+ safe_netlink_send(__FILE__, __LINE__, fd, nl_header, payload)
+
+/** @private */
+static inline ssize_t safe_netlink_recv(const char *file, const int lineno,
+ int fd, char *nl_headers_buf,
+ size_t buf_len)
+{
+ struct iovec iov = { nl_headers_buf, buf_len };
+ struct sockaddr_nl sa;
+ struct msghdr msg = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1
+ };
+
+ return safe_recvmsg(file, lineno, 0, fd, &msg, 0);
+}
+
+/**
+ * Receives a netlink message using safe_recvmsg().
+ *
+ * @param fd netlink socket file descriptor.
+ * @param nl_header_buf buffer to contain the received netlink header structure.
+ * @param buf_len The length of the header buffer. Must be greater than the page
+ * size.
+ *
+ * @return The number of bytes received.
+ */
+#define SAFE_NETLINK_RECV(fd, nl_header_buf, buf_len) \
+ safe_netlink_recv(__FILE__, __LINE__, fd, nl_header_buf, buf_len)
+
+#endif /* TST_NETLINK_H */
diff --git a/src/kernel/tests/include/tst_numa.h b/src/kernel/tests/include/tst_numa.h
new file mode 100644
index 0000000..846e093
--- /dev/null
+++ b/src/kernel/tests/include/tst_numa.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_NUMA_H__
+#define TST_NUMA_H__
+
+#include <string.h>
+
+/**
+ * Numa nodemap.
+ */
+struct tst_nodemap {
+ /** Number of nodes in map */
+ unsigned int cnt;
+ /** Page allocation counters */
+ unsigned int *counters;
+ /** Array of numa ids */
+ unsigned int map[];
+};
+
+/**
+ * Clears numa counters. The counters are lazy-allocated on first call of this function.
+ *
+ * @nodes Numa nodemap.
+ */
+void tst_nodemap_reset_counters(struct tst_nodemap *nodes);
+
+/**
+ * Prints pages allocated per each node.
+ *
+ * @nodes Numa nodemap.
+ */
+void tst_nodemap_print_counters(struct tst_nodemap *nodes);
+
+/**
+ * Returns a name for a mempolicy/mbind mode.
+ *
+ * @mode Numa mempolicy mode.
+ */
+const char *tst_numa_mode_name(int mode);
+
+/**
+ * Maps pages into memory, if path is NULL the mapping is anonymous otherwise is backed by the file.
+ *
+ * @path Path to a file, if not NULL mapping is file based.
+ * @size Mapping size.
+ */
+void *tst_numa_map(const char *path, size_t size);
+
+/*
+ * Writes to memory in order to get the pages faulted.
+ *
+ * @ptr Start of the mapping.
+ * @size Size of the mapping.
+ */
+static inline void tst_numa_fault(void *ptr, size_t size)
+{
+ memset(ptr, 'a', size);
+}
+
+/*
+ * Frees the memory.
+ *
+ * @ptr Start of the mapping.
+ * @size Size of the mapping.
+ */
+static inline void tst_numa_unmap(void *ptr, size_t size)
+{
+ SAFE_MUNMAP(ptr, size);
+}
+
+/**
+ * Check on which numa node resides each page of the mapping starting at ptr
+ * and continuing pages long and increases nodemap counters accordingly.
+ *
+ * @nodes Nodemap with initialized counters.
+ * @ptr Pointer to start of a mapping.
+ * @size Size of the mapping.
+ */
+void tst_nodemap_count_pages(struct tst_nodemap *nodes, void *ptr, size_t size);
+
+/**
+ * Frees nodemap.
+ *
+ * @nodes Numa nodemap to be freed.
+ */
+void tst_nodemap_free(struct tst_nodemap *nodes);
+
+/**
+ * Bitflags for tst_get_nodemap() function.
+ */
+enum tst_numa_types {
+ TST_NUMA_ANY = 0x00,
+ TST_NUMA_MEM = 0x01,
+};
+
+/**
+ * Allocates and returns numa node map, which is an array of numa nodes which
+ * contain desired resources e.g. memory.
+ *
+ * @type Bitflags of enum tst_numa_types specifying desired resources.
+ * @min_mem_kb Minimal free RAM on memory nodes, if given node has less than
+ * requested amount of free+buffers memory it's not included in
+ * the resulting list of nodes.
+ *
+ * @return On success returns allocated and initialized struct tst_nodemap which contains
+ * array of numa node ids that contains desired resources.
+ */
+struct tst_nodemap *tst_get_nodemap(int type, size_t min_mem_kb);
+
+#endif /* TST_NUMA_H__ */
diff --git a/src/kernel/tests/include/tst_path_has_mnt_flags.h b/src/kernel/tests/include/tst_path_has_mnt_flags.h
new file mode 100644
index 0000000..a9e1f40
--- /dev/null
+++ b/src/kernel/tests/include/tst_path_has_mnt_flags.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef TST_PATH_HAS_MNT_FLAGS_H__
+#define TST_PATH_HAS_MNT_FLAGS_H__
+
+#ifdef TST_TEST_H__
+# define tst_path_has_mnt_flags(...) tst_path_has_mnt_flags_(NULL, __VA_ARGS__)
+#else
+# define tst_path_has_mnt_flags tst_path_has_mnt_flags_
+#endif
+
+/* lib/tst_path_has_mnt_flags.c
+ *
+ * Check whether a path is on a filesystem that is mounted with
+ * specified flags
+ * @path: path to file, if path is NULL tst_tmpdir is used.
+ * @flags: NULL or NULL terminated array of mount flags
+ *
+ * Return: 0..n - number of flags matched
+ */
+int tst_path_has_mnt_flags_(void (*cleanup_fn)(void),
+ const char *path, const char *flags[]);
+
+#endif /* TST_PATH_HAS_MNT_FLAGS_H__ */
diff --git a/src/kernel/tests/include/tst_pid.h b/src/kernel/tests/include/tst_pid.h
new file mode 100644
index 0000000..9ba1abb
--- /dev/null
+++ b/src/kernel/tests/include/tst_pid.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_PID_H__
+#define TST_PID_H__
+
+#include <sys/types.h>
+
+/*
+ * Get a pid value not used by the OS
+ */
+pid_t tst_get_unused_pid_(void (*cleanup_fn)(void));
+
+/*
+ * Returns number of free pids by substarction of the number of pids
+ * currently used ('ps -eT') from max_pids
+ */
+int tst_get_free_pids_(void (*cleanup_fn)(void));
+
+#ifdef TST_TEST_H__
+static inline pid_t tst_get_unused_pid(void)
+{
+ return tst_get_unused_pid_(NULL);
+}
+
+static inline int tst_get_free_pids(void)
+{
+ return tst_get_free_pids_(NULL);
+}
+#else
+static inline pid_t tst_get_unused_pid(void (*cleanup_fn)(void))
+{
+ return tst_get_unused_pid_(cleanup_fn);
+}
+
+static inline int tst_get_free_pids(void (*cleanup_fn)(void))
+{
+ return tst_get_free_pids_(cleanup_fn);
+}
+#endif
+
+#endif /* TST_PID_H__ */
diff --git a/src/kernel/tests/include/tst_private.h b/src/kernel/tests/include/tst_private.h
new file mode 100644
index 0000000..e30d347
--- /dev/null
+++ b/src/kernel/tests/include/tst_private.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2019 Petr Vorel <pvorel@suse.cz>
+ *
+ * Internal helper functions for the shell library. Do not use directly
+ * in test programs.
+ */
+
+#ifndef TST_PRIVATE_H_
+#define TST_PRIVATE_H_
+
+#include <stdio.h>
+#include <netdb.h>
+
+#define MAX_IPV4_PREFIX 32
+#define MAX_IPV6_PREFIX 128
+
+#define tst_res_comment(...) { \
+ fprintf(stderr, "# "); \
+ tst_res(__VA_ARGS__); } \
+
+
+#define tst_brk_comment(...) { \
+ fprintf(stderr, "# "); \
+ tst_brk(TCONF, __VA_ARGS__); } \
+
+void tst_print_svar(const char *name, const char *val);
+void tst_print_svar_change(const char *name, const char *val);
+
+int tst_get_prefix(const char *ip_str, int is_ipv6);
+
+#endif
diff --git a/src/kernel/tests/include/tst_process_state.h b/src/kernel/tests/include/tst_process_state.h
new file mode 100644
index 0000000..c32aa58
--- /dev/null
+++ b/src/kernel/tests/include/tst_process_state.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2012-2014 Cyril Hrubis chrubis@suse.cz
+ */
+
+ /*
+
+ These functions helps you wait till a process with given pid changes state.
+ This is for example useful when you need to wait in parent until child
+ blocks.
+
+ */
+
+#ifndef TST_PROCESS_STATE__
+#define TST_PROCESS_STATE__
+
+#include <unistd.h>
+
+/*
+ * Waits for process state change.
+ *
+ * The state is one of the following:
+ *
+ * R - process is running
+ * S - process is sleeping
+ * D - process sleeping uninterruptibly
+ * Z - zombie process
+ * T - process is traced
+ */
+#ifdef TST_TEST_H__
+
+#define TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) \
+ tst_process_state_wait(__FILE__, __LINE__, NULL, \
+ (pid), (state), (msec_timeout))
+#else
+/*
+ * The same as above but does not use tst_brkm() interface.
+ *
+ * This function is intended to be used from child processes.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+int tst_process_state_wait2(pid_t pid, const char state);
+
+# define TST_PROCESS_STATE_WAIT(cleanup_fn, pid, state) \
+ tst_process_state_wait(__FILE__, __LINE__, (cleanup_fn), \
+ (pid), (state), 0)
+#endif
+
+int tst_process_state_wait(const char *file, const int lineno,
+ void (*cleanup_fn)(void), pid_t pid,
+ const char state, unsigned int msec_timeout);
+
+#endif /* TST_PROCESS_STATE__ */
diff --git a/src/kernel/tests/include/tst_res_flags.h b/src/kernel/tests/include/tst_res_flags.h
new file mode 100644
index 0000000..8eda2f8
--- /dev/null
+++ b/src/kernel/tests/include/tst_res_flags.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) Linux Test Project, 2014
+ */
+
+#ifndef TST_RES_FLAGS_H
+#define TST_RES_FLAGS_H
+
+/* Use low 6 bits to encode test type */
+#define TTYPE_MASK 0x3f
+#define TPASS 0 /* Test passed flag */
+#define TFAIL 1 /* Test failed flag */
+#define TBROK 2 /* Test broken flag */
+#define TWARN 4 /* Test warning flag */
+#define TINFO 16 /* Test information flag */
+#define TCONF 32 /* Test not appropriate for configuration flag */
+#define TTYPE_RESULT(ttype) ((ttype) & TTYPE_MASK)
+
+#define TERRNO 0x100 /* Append errno information to output */
+#define TTERRNO 0x200 /* Append TEST_ERRNO information to output */
+#define TRERRNO 0x400 /* Capture errno information from TEST_RETURN to
+ output; useful for pthread-like APIs :). */
+
+#endif /* TST_RES_FLAGS_H */
diff --git a/src/kernel/tests/include/tst_safe_clocks.h b/src/kernel/tests/include/tst_safe_clocks.h
new file mode 100644
index 0000000..5909f40
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_clocks.h
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019, Linux Test Project
+ * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
+ * Email : code@zilogic.com
+ */
+
+#ifndef TST_SAFE_CLOCKS_H__
+#define TST_SAFE_CLOCKS_H__
+
+#include <time.h>
+#include <sys/timex.h>
+#include "tst_test.h"
+#include "tst_clocks.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+
+static inline void safe_clock_getres(const char *file, const int lineno,
+ clockid_t clk_id, struct timespec *res)
+{
+ int rval;
+
+ rval = clock_getres(clk_id, res);
+ if (rval != 0) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d clock_getres(%s) failed",
+ file, lineno, tst_clock_name(clk_id));
+ }
+}
+
+static inline void safe_clock_gettime(const char *file, const int lineno,
+ clockid_t clk_id, struct timespec *tp)
+{
+ int rval;
+
+ rval = clock_gettime(clk_id, tp);
+ if (rval != 0) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d clock_gettime(%s) failed",
+ file, lineno, tst_clock_name(clk_id));
+ }
+}
+
+
+static inline void safe_clock_settime(const char *file, const int lineno,
+ clockid_t clk_id, struct timespec *tp)
+{
+ int rval;
+
+ rval = clock_settime(clk_id, tp);
+ if (rval != 0) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d clock_gettime(%s) failed",
+ file, lineno, tst_clock_name(clk_id));
+ }
+}
+
+static inline int safe_timer_create(const char *file, const int lineno,
+ clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
+{
+ int ret;
+
+ errno = 0;
+ ret = timer_create(clockid, sevp, timerid);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "timer_create(%s) failed", tst_clock_name(clockid));
+ } else if (ret) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid timer_create(%s) return value %d",
+ tst_clock_name(clockid), ret);
+ }
+
+ return ret;
+}
+
+static inline int safe_timer_settime(const char *file, const int lineno,
+ timer_t timerid, int flags, const struct itimerspec *new_value,
+ struct itimerspec *old_value)
+{
+ int ret;
+
+ errno = 0;
+ ret = timer_settime(timerid, flags, new_value, old_value);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "timer_settime() failed");
+ } else if (ret) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid timer_settime() return value %d", ret);
+ }
+
+ return ret;
+}
+
+static inline int safe_timer_gettime(const char *file, const int lineno,
+ timer_t timerid, struct itimerspec *curr_value)
+{
+ int ret;
+
+ errno = 0;
+ ret = timer_gettime(timerid, curr_value);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "timer_gettime() failed");
+ } else if (ret) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid timer_gettime() return value %d", ret);
+ }
+
+ return ret;
+}
+
+static inline int safe_timer_delete(const char *file, const int lineno,
+ timer_t timerid)
+{
+ int ret;
+
+ errno = 0;
+ ret = timer_delete(timerid);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO, "timer_delete() failed");
+ } else if (ret) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid timer_delete() return value %d", ret);
+ }
+
+ return ret;
+}
+
+#define SAFE_CLOCK_GETRES(clk_id, res)\
+ safe_clock_getres(__FILE__, __LINE__, (clk_id), (res))
+
+#define SAFE_CLOCK_GETTIME(clk_id, tp)\
+ safe_clock_gettime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_CLOCK_SETTIME(clk_id, tp)\
+ safe_clock_settime(__FILE__, __LINE__, (clk_id), (tp))
+
+#define SAFE_TIMER_CREATE(clockid, sevp, timerid)\
+ safe_timer_create(__FILE__, __LINE__, (clockid), (sevp), (timerid))
+
+#define SAFE_TIMER_SETTIME(timerid, flags, new_value, old_value)\
+ safe_timer_settime(__FILE__, __LINE__, (timerid), (flags),\
+ (new_value), (old_value))
+
+#define SAFE_TIMER_GETTIME(timerid, curr_value)\
+ safe_timer_gettime(__FILE__, __LINE__, (timerid), (curr_value))
+
+#define SAFE_TIMER_DELETE(timerid)\
+ safe_timer_delete(__FILE__, __LINE__, timerid)
+
+#endif /* SAFE_CLOCKS_H__ */
diff --git a/src/kernel/tests/include/tst_safe_file_ops.h b/src/kernel/tests/include/tst_safe_file_ops.h
new file mode 100644
index 0000000..894c161
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_file_ops.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz
+ */
+
+#ifndef TST_SAFE_FILE_OPS
+#define TST_SAFE_FILE_OPS
+
+#include "safe_file_ops_fn.h"
+
+#define SAFE_FILE_SCANF(path, fmt, ...) \
+ safe_file_scanf(__FILE__, __LINE__, NULL, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define FILE_LINES_SCANF(path, fmt, ...) \
+ file_lines_scanf(__FILE__, __LINE__, NULL, 0,\
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_FILE_LINES_SCANF(path, fmt, ...) \
+ file_lines_scanf(__FILE__, __LINE__, NULL, 1,\
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_READ_MEMINFO(item) \
+ ({long tst_rval; \
+ SAFE_FILE_LINES_SCANF("/proc/meminfo", item " %ld", \
+ &tst_rval); \
+ tst_rval;})
+
+#define FILE_PRINTF(path, fmt, ...) \
+ file_printf(__FILE__, __LINE__, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_FILE_PRINTF(path, fmt, ...) \
+ safe_file_printf(__FILE__, __LINE__, NULL, \
+ (path), (fmt), ## __VA_ARGS__)
+
+#define SAFE_CP(src, dst) \
+ safe_cp(__FILE__, __LINE__, NULL, (src), (dst))
+
+#define SAFE_TOUCH(pathname, mode, times) \
+ safe_touch(__FILE__, __LINE__, NULL, \
+ (pathname), (mode), (times))
+
+#define SAFE_MOUNT_OVERLAY() \
+ ((void) mount_overlay(__FILE__, __LINE__, 1))
+
+#define TST_MOUNT_OVERLAY() \
+ (mount_overlay(__FILE__, __LINE__, 0) == 0)
+
+#endif /* TST_SAFE_FILE_OPS */
diff --git a/src/kernel/tests/include/tst_safe_macros.h b/src/kernel/tests/include/tst_safe_macros.h
new file mode 100644
index 0000000..053c3bc
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_macros.h
@@ -0,0 +1,606 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2010-2018 Linux Test Project
+ * Copyright (c) 2011-2015 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_SAFE_MACROS_H__
+#define TST_SAFE_MACROS_H__
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/sysinfo.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <grp.h>
+
+#include "safe_macros_fn.h"
+#include "tst_cmd.h"
+
+#define SAFE_BASENAME(path) \
+ safe_basename(__FILE__, __LINE__, NULL, (path))
+
+#define SAFE_CHDIR(path) \
+ safe_chdir(__FILE__, __LINE__, NULL, (path))
+
+#define SAFE_CLOSE(fd) do { \
+ safe_close(__FILE__, __LINE__, NULL, (fd)); \
+ fd = -1; \
+ } while (0)
+
+#define SAFE_CREAT(pathname, mode) \
+ safe_creat(__FILE__, __LINE__, NULL, (pathname), (mode))
+
+#define SAFE_CHROOT(path) \
+ safe_chroot(__FILE__, __LINE__, (path))
+int safe_chroot(const char *file, const int lineno, const char *path);
+
+#define SAFE_DIRNAME(path) \
+ safe_dirname(__FILE__, __LINE__, NULL, (path))
+
+static inline int safe_dup(const char *file, const int lineno,
+ int oldfd)
+{
+ int rval;
+
+ rval = dup(oldfd);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "dup(%i) failed", oldfd);
+ }
+
+ return rval;
+}
+#define SAFE_DUP(oldfd) \
+ safe_dup(__FILE__, __LINE__, (oldfd))
+
+#define SAFE_GETCWD(buf, size) \
+ safe_getcwd(__FILE__, __LINE__, NULL, (buf), (size))
+
+#define SAFE_GETPWNAM(name) \
+ safe_getpwnam(__FILE__, __LINE__, NULL, (name))
+
+#define SAFE_GETRUSAGE(who, usage) \
+ safe_getrusage(__FILE__, __LINE__, NULL, (who), (usage))
+
+#define SAFE_MALLOC(size) \
+ safe_malloc(__FILE__, __LINE__, NULL, (size))
+
+#define SAFE_MKDIR(pathname, mode) \
+ safe_mkdir(__FILE__, __LINE__, NULL, (pathname), (mode))
+
+#define SAFE_RMDIR(pathname) \
+ safe_rmdir(__FILE__, __LINE__, NULL, (pathname))
+
+#define SAFE_MUNMAP(addr, length) \
+ safe_munmap(__FILE__, __LINE__, NULL, (addr), (length))
+
+#define SAFE_OPEN(pathname, oflags, ...) \
+ safe_open(__FILE__, __LINE__, NULL, (pathname), (oflags), \
+ ##__VA_ARGS__)
+
+#define SAFE_PIPE(fildes) \
+ safe_pipe(__FILE__, __LINE__, NULL, (fildes))
+
+int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags);
+
+#define SAFE_PIPE2(fildes, flags) \
+ safe_pipe2(__FILE__, __LINE__, (fildes), (flags))
+
+#define SAFE_READ(len_strict, fildes, buf, nbyte) \
+ safe_read(__FILE__, __LINE__, NULL, (len_strict), (fildes), (buf), (nbyte))
+
+#define SAFE_SETEGID(egid) \
+ safe_setegid(__FILE__, __LINE__, NULL, (egid))
+
+#define SAFE_SETEUID(euid) \
+ safe_seteuid(__FILE__, __LINE__, NULL, (euid))
+
+#define SAFE_SETGID(gid) \
+ safe_setgid(__FILE__, __LINE__, NULL, (gid))
+
+#define SAFE_SETUID(uid) \
+ safe_setuid(__FILE__, __LINE__, NULL, (uid))
+
+int safe_setregid(const char *file, const int lineno,
+ gid_t rgid, gid_t egid);
+
+#define SAFE_SETREGID(rgid, egid) \
+ safe_setregid(__FILE__, __LINE__, (rgid), (egid))
+
+int safe_setreuid(const char *file, const int lineno,
+ uid_t ruid, uid_t euid);
+
+#define SAFE_SETREUID(ruid, euid) \
+ safe_setreuid(__FILE__, __LINE__, (ruid), (euid))
+
+#define SAFE_GETRESUID(ruid, euid, suid) \
+ safe_getresuid(__FILE__, __LINE__, NULL, (ruid), (euid), (suid))
+
+#define SAFE_GETRESGID(rgid, egid, sgid) \
+ safe_getresgid(__FILE__, __LINE__, NULL, (rgid), (egid), (sgid))
+
+int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid);
+
+#define SAFE_SETPGID(pid, pgid) \
+ safe_setpgid(__FILE__, __LINE__, (pid), (pgid));
+
+pid_t safe_getpgid(const char *file, const int lineno, pid_t pid);
+
+#define SAFE_GETPGID(pid) \
+ safe_getpgid(__FILE__, __LINE__, (pid))
+
+#define SAFE_UNLINK(pathname) \
+ safe_unlink(__FILE__, __LINE__, NULL, (pathname))
+
+#define SAFE_LINK(oldpath, newpath) \
+ safe_link(__FILE__, __LINE__, NULL, (oldpath), (newpath))
+
+#define SAFE_LINKAT(olddirfd, oldpath, newdirfd, newpath, flags) \
+ safe_linkat(__FILE__, __LINE__, NULL, (olddirfd), (oldpath), \
+ (newdirfd), (newpath), (flags))
+
+#define SAFE_READLINK(path, buf, bufsize) \
+ safe_readlink(__FILE__, __LINE__, NULL, (path), (buf), (bufsize))
+
+#define SAFE_SYMLINK(oldpath, newpath) \
+ safe_symlink(__FILE__, __LINE__, NULL, (oldpath), (newpath))
+
+#define SAFE_WRITE(len_strict, fildes, buf, nbyte) \
+ safe_write(__FILE__, __LINE__, NULL, (len_strict), (fildes), (buf), (nbyte))
+
+#define SAFE_STRTOL(str, min, max) \
+ safe_strtol(__FILE__, __LINE__, NULL, (str), (min), (max))
+
+#define SAFE_STRTOUL(str, min, max) \
+ safe_strtoul(__FILE__, __LINE__, NULL, (str), (min), (max))
+
+#define SAFE_SYSCONF(name) \
+ safe_sysconf(__FILE__, __LINE__, NULL, name)
+
+#define SAFE_CHMOD(path, mode) \
+ safe_chmod(__FILE__, __LINE__, NULL, (path), (mode))
+
+#define SAFE_FCHMOD(fd, mode) \
+ safe_fchmod(__FILE__, __LINE__, NULL, (fd), (mode))
+
+#define SAFE_CHOWN(path, owner, group) \
+ safe_chown(__FILE__, __LINE__, NULL, (path), (owner), (group))
+
+#define SAFE_FCHOWN(fd, owner, group) \
+ safe_fchown(__FILE__, __LINE__, NULL, (fd), (owner), (group))
+
+#define SAFE_WAIT(status) \
+ safe_wait(__FILE__, __LINE__, NULL, (status))
+
+#define SAFE_WAITPID(pid, status, opts) \
+ safe_waitpid(__FILE__, __LINE__, NULL, (pid), (status), (opts))
+
+#define SAFE_KILL(pid, sig) \
+ safe_kill(__FILE__, __LINE__, NULL, (pid), (sig))
+
+#define SAFE_MEMALIGN(alignment, size) \
+ safe_memalign(__FILE__, __LINE__, NULL, (alignment), (size))
+
+#define SAFE_MKFIFO(pathname, mode) \
+ safe_mkfifo(__FILE__, __LINE__, NULL, (pathname), (mode))
+
+#define SAFE_RENAME(oldpath, newpath) \
+ safe_rename(__FILE__, __LINE__, NULL, (oldpath), (newpath))
+
+#define SAFE_MOUNT(source, target, filesystemtype, \
+ mountflags, data) \
+ safe_mount(__FILE__, __LINE__, NULL, (source), (target), \
+ (filesystemtype), (mountflags), (data))
+
+#define SAFE_UMOUNT(target) \
+ safe_umount(__FILE__, __LINE__, NULL, (target))
+
+#define SAFE_OPENDIR(name) \
+ safe_opendir(__FILE__, __LINE__, NULL, (name))
+
+#define SAFE_CLOSEDIR(dirp) \
+ safe_closedir(__FILE__, __LINE__, NULL, (dirp))
+
+#define SAFE_READDIR(dirp) \
+ safe_readdir(__FILE__, __LINE__, NULL, (dirp))
+
+#define SAFE_IOCTL(fd, request, ...) \
+ ({int tst_ret_ = ioctl(fd, request, ##__VA_ARGS__); \
+ tst_ret_ < 0 ? \
+ tst_brk(TBROK | TERRNO, \
+ "ioctl(%i,%s,...) failed", fd, #request), 0 \
+ : tst_ret_;})
+
+#define SAFE_FCNTL(fd, cmd, ...) \
+ ({int tst_ret_ = fcntl(fd, cmd, ##__VA_ARGS__); \
+ tst_ret_ == -1 ? \
+ tst_brk(TBROK | TERRNO, \
+ "fcntl(%i,%s,...) failed", fd, #cmd), 0 \
+ : tst_ret_;})
+
+/*
+ * following functions are inline because the behaviour may depend on
+ * -D_FILE_OFFSET_BITS=64 -DOFF_T=off64_t compile flags
+ */
+
+static inline void *safe_mmap(const char *file, const int lineno,
+ void *addr, size_t length,
+ int prot, int flags, int fd, off_t offset)
+{
+ void *rval;
+
+ rval = mmap(addr, length, prot, flags, fd, offset);
+ if (rval == MAP_FAILED) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "mmap(%p,%zu,%d,%d,%d,%ld) failed",
+ addr, length, prot, flags, fd, (long) offset);
+ }
+
+ return rval;
+}
+#define SAFE_MMAP(addr, length, prot, flags, fd, offset) \
+ safe_mmap(__FILE__, __LINE__, (addr), (length), (prot), \
+ (flags), (fd), (offset))
+
+static inline int safe_ftruncate(const char *file, const int lineno,
+ int fd, off_t length)
+{
+ int rval;
+
+ rval = ftruncate(fd, length);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "ftruncate(%d,%ld) failed",
+ fd, (long)length);
+ }
+
+ return rval;
+}
+#define SAFE_FTRUNCATE(fd, length) \
+ safe_ftruncate(__FILE__, __LINE__, (fd), (length))
+
+static inline int safe_truncate(const char *file, const int lineno,
+ const char *path, off_t length)
+{
+ int rval;
+
+ rval = truncate(path, length);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "truncate(%s,%ld) failed",
+ path, (long)length);
+ }
+
+ return rval;
+}
+#define SAFE_TRUNCATE(path, length) \
+ safe_truncate(__FILE__, __LINE__, (path), (length))
+
+static inline int safe_stat(const char *file, const int lineno,
+ const char *path, struct stat *buf)
+{
+ int rval;
+
+ rval = stat(path, buf);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "stat(%s,%p) failed", path, buf);
+ }
+
+ return rval;
+}
+#define SAFE_STAT(path, buf) \
+ safe_stat(__FILE__, __LINE__, (path), (buf))
+
+static inline int safe_fstat(const char *file, const int lineno,
+ int fd, struct stat *buf)
+{
+ int rval;
+
+ rval = fstat(fd, buf);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "fstat(%d,%p) failed", fd, buf);
+ }
+
+ return rval;
+}
+#define SAFE_FSTAT(fd, buf) \
+ safe_fstat(__FILE__, __LINE__, (fd), (buf))
+
+static inline int safe_lstat(const char *file, const int lineno,
+ const char *path, struct stat *buf)
+{
+ int rval;
+
+ rval = lstat(path, buf);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "lstat(%s,%p) failed", path, buf);
+ }
+
+ return rval;
+}
+#define SAFE_LSTAT(path, buf) \
+ safe_lstat(__FILE__, __LINE__, (path), (buf))
+
+static inline int safe_statfs(const char *file, const int lineno,
+ const char *path, struct statfs *buf)
+{
+ int rval;
+
+ rval = statfs(path, buf);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "statfs(%s,%p) failed", path, buf);
+ }
+
+ return rval;
+}
+#define SAFE_STATFS(path, buf) \
+ safe_statfs(__FILE__, __LINE__, (path), (buf))
+
+static inline off_t safe_lseek(const char *file, const int lineno,
+ int fd, off_t offset, int whence)
+{
+ off_t rval;
+
+ rval = lseek(fd, offset, whence);
+
+ if (rval == (off_t) -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "lseek(%d,%ld,%d) failed",
+ fd, (long)offset, whence);
+ }
+
+ return rval;
+}
+#define SAFE_LSEEK(fd, offset, whence) \
+ safe_lseek(__FILE__, __LINE__, (fd), (offset), (whence))
+
+static inline int safe_getrlimit(const char *file, const int lineno,
+ int resource, struct rlimit *rlim)
+{
+ int rval;
+
+ rval = getrlimit(resource, rlim);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "getrlimit(%d,%p) failed",
+ resource, rlim);
+ }
+
+ return rval;
+}
+#define SAFE_GETRLIMIT(resource, rlim) \
+ safe_getrlimit(__FILE__, __LINE__, (resource), (rlim))
+
+static inline int safe_setrlimit(const char *file, const int lineno,
+ int resource, const struct rlimit *rlim)
+{
+ int rval;
+
+ rval = setrlimit(resource, rlim);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "setrlimit(%d,%p) failed",
+ resource, rlim);
+ }
+
+ return rval;
+}
+#define SAFE_SETRLIMIT(resource, rlim) \
+ safe_setrlimit(__FILE__, __LINE__, (resource), (rlim))
+
+typedef void (*sighandler_t)(int);
+static inline sighandler_t safe_signal(const char *file, const int lineno,
+ int signum, sighandler_t handler)
+{
+ sighandler_t rval;
+
+ rval = signal(signum, handler);
+
+ if (rval == SIG_ERR) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "signal(%d,%p) failed",
+ signum, handler);
+ }
+
+ return rval;
+}
+
+#define SAFE_SIGNAL(signum, handler) \
+ safe_signal(__FILE__, __LINE__, (signum), (handler))
+
+int safe_sigaction(const char *file, const int lineno,
+ int signum, const struct sigaction *act,
+ struct sigaction *oldact);
+#define SAFE_SIGACTION(signum, act, oldact) \
+ safe_sigaction(__FILE__, __LINE__, (signum), (act), (oldact))
+
+void safe_sigaddset(const char *file, const int lineno,
+ sigset_t *sigs, int signo);
+#define SAFE_SIGADDSET(sigs, signo) \
+ safe_sigaddset(__FILE__, __LINE__, (sigs), (signo))
+
+void safe_sigdelset(const char *file, const int lineno,
+ sigset_t *sigs, int signo);
+#define SAFE_SIGDELSET(sigs, signo) \
+ safe_sigdelset(__FILE__, __LINE__, (sigs), (signo))
+
+void safe_sigemptyset(const char *file, const int lineno,
+ sigset_t *sigs);
+#define SAFE_SIGEMPTYSET(sigs) \
+ safe_sigemptyset(__FILE__, __LINE__, (sigs))
+
+void safe_sigfillset(const char *file, const int lineno,
+ sigset_t *sigs);
+#define SAFE_SIGFILLSET(sigs) \
+ safe_sigfillset(__FILE__, __LINE__, (sigs))
+
+void safe_sigprocmask(const char *file, const int lineno,
+ int how, sigset_t *set, sigset_t *oldset);
+#define SAFE_SIGPROCMASK(how, set, oldset) \
+ safe_sigprocmask(__FILE__, __LINE__, (how), (set), (oldset))
+
+void safe_sigwait(const char *file, const int lineno,
+ sigset_t *set, int *sig);
+#define SAFE_SIGWAIT(set, sig) \
+ safe_sigwait(__FILE__, __LINE__, (set), (sig))
+
+#define SAFE_EXECLP(file, arg, ...) do { \
+ execlp((file), (arg), ##__VA_ARGS__); \
+ tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \
+ "execlp(%s, %s, ...) failed", file, arg); \
+ } while (0)
+
+#define SAFE_EXECL(file, arg, ...) do { \
+ execl((file), (arg), ##__VA_ARGS__); \
+ tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \
+ "execl(%s, %s, ...) failed", file, arg); \
+ } while (0)
+
+int safe_getpriority(const char *file, const int lineno, int which, id_t who);
+#define SAFE_GETPRIORITY(which, who) \
+ safe_getpriority(__FILE__, __LINE__, (which), (who))
+
+struct group *safe_getgrnam(const char *file, const int lineno,
+ const char *name);
+#define SAFE_GETGRNAM(name) \
+ safe_getgrnam(__FILE__, __LINE__, (name))
+
+struct group *safe_getgrnam_fallback(const char *file, const int lineno,
+ const char *name, const char *fallback);
+#define SAFE_GETGRNAM_FALLBACK(name, fallback) \
+ safe_getgrnam_fallback(__FILE__, __LINE__, (name), (fallback))
+
+struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid);
+#define SAFE_GETGRGID(gid) \
+ safe_getgrgid(__FILE__, __LINE__, (gid))
+
+ssize_t safe_getxattr(const char *file, const int lineno, const char *path,
+ const char *name, void *value, size_t size);
+#define SAFE_GETXATTR(path, name, value, size) \
+ safe_getxattr(__FILE__, __LINE__, (path), (name), (value), (size))
+
+int safe_setxattr(const char *file, const int lineno, const char *path,
+ const char *name, const void *value, size_t size, int flags);
+#define SAFE_SETXATTR(path, name, value, size, flags) \
+ safe_setxattr(__FILE__, __LINE__, (path), (name), (value), (size), (flags))
+
+int safe_lsetxattr(const char *file, const int lineno, const char *path,
+ const char *name, const void *value, size_t size, int flags);
+#define SAFE_LSETXATTR(path, name, value, size, flags) \
+ safe_lsetxattr(__FILE__, __LINE__, (path), (name), (value), (size), (flags))
+
+int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name,
+ const void *value, size_t size, int flags);
+#define SAFE_FSETXATTR(fd, name, value, size, flags) \
+ safe_fsetxattr(__FILE__, __LINE__, (fd), (name), (value), (size), (flags))
+
+int safe_removexattr(const char *file, const int lineno, const char *path,
+ const char *name);
+#define SAFE_REMOVEXATTR(path, name) \
+ safe_removexattr(__FILE__, __LINE__, (path), (name))
+
+int safe_lremovexattr(const char *file, const int lineno, const char *path,
+ const char *name);
+#define SAFE_LREMOVEXATTR(path, name) \
+ safe_lremovexattr(__FILE__, __LINE__, (path), (name))
+
+int safe_fremovexattr(const char *file, const int lineno, int fd,
+ const char *name);
+#define SAFE_FREMOVEXATTR(fd, name) \
+ safe_fremovexattr(__FILE__, __LINE__, (fd), (name))
+
+int safe_fsync(const char *file, const int lineno, int fd);
+#define SAFE_FSYNC(fd) safe_fsync(__FILE__, __LINE__, (fd))
+
+int safe_setsid(const char *file, const int lineno);
+#define SAFE_SETSID() safe_setsid(__FILE__, __LINE__)
+
+int safe_mknod(const char *file, const int lineno, const char *pathname,
+ mode_t mode, dev_t dev);
+#define SAFE_MKNOD(pathname, mode, dev) \
+ safe_mknod(__FILE__, __LINE__, (pathname), (mode), (dev))
+
+int safe_mlock(const char *file, const int lineno, const char *addr,
+ size_t len);
+#define SAFE_MLOCK(addr, len) safe_mlock(__FILE__, __LINE__, (addr), (len))
+
+int safe_munlock(const char *file, const int lineno, const char *addr,
+ size_t len);
+#define SAFE_MUNLOCK(addr, len) safe_munlock(__FILE__, __LINE__, (addr), (len))
+
+int safe_mincore(const char *file, const int lineno, void *start,
+ size_t length, unsigned char *vec);
+#define SAFE_MINCORE(start, length, vec) \
+ safe_mincore(__FILE__, __LINE__, (start), (length), (vec))
+
+int safe_fanotify_init(const char *file, const int lineno,
+ unsigned int flags, unsigned int event_f_flags);
+#define SAFE_FANOTIFY_INIT(fan, mode) \
+ safe_fanotify_init(__FILE__, __LINE__, (fan), (mode))
+
+int safe_personality(const char *filename, unsigned int lineno,
+ unsigned long persona);
+#define SAFE_PERSONALITY(persona) safe_personality(__FILE__, __LINE__, persona)
+
+#define SAFE_SETENV(name, value, overwrite) do { \
+ if (setenv(name, value, overwrite)) { \
+ tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \
+ "setenv(%s, %s, %d) failed", \
+ name, value, overwrite); \
+ } \
+ } while (0)
+
+void safe_unshare(const char *file, const int lineno, int flags);
+#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags))
+
+void safe_setns(const char *file, const int lineno, int fd, int nstype);
+#define SAFE_SETNS(fd, nstype) safe_setns(__FILE__, __LINE__, (fd), (nstype));
+
+static inline void safe_cmd(const char *file, const int lineno, const char *const argv[],
+ const char *stdout_path, const char *stderr_path)
+{
+ int rval;
+
+ switch ((rval = tst_cmd(argv, stdout_path, stderr_path,
+ TST_CMD_PASS_RETVAL | TST_CMD_TCONF_ON_MISSING))) {
+ case 0:
+ break;
+ default:
+ tst_brk(TBROK, "%s:%d: %s failed (%d)", file, lineno, argv[0], rval);
+ }
+}
+#define SAFE_CMD(argv, stdout_path, stderr_path) \
+ safe_cmd(__FILE__, __LINE__, (argv), (stdout_path), (stderr_path))
+/*
+ * SAFE_PTRACE() treats any non-zero return value as error. Don't use it
+ * for requests like PTRACE_PEEK* or PTRACE_SECCOMP_GET_FILTER which use
+ * the return value to pass arbitrary data.
+ */
+long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid,
+ void *addr, void *data);
+#define SAFE_PTRACE(req, pid, addr, data) \
+ tst_safe_ptrace(__FILE__, __LINE__, req, pid, addr, data)
+
+int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info);
+#define SAFE_SYSINFO(info) \
+ safe_sysinfo(__FILE__, __LINE__, (info))
+
+#endif /* SAFE_MACROS_H__ */
diff --git a/src/kernel/tests/include/tst_safe_net.h b/src/kernel/tests/include/tst_safe_net.h
new file mode 100644
index 0000000..78a488a
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_net.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_SAFE_NET_H__
+#define TST_SAFE_NET_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+
+#include "safe_net_fn.h"
+#include "tst_net.h"
+
+#define SAFE_SOCKET(domain, type, protocol) \
+ safe_socket(__FILE__, __LINE__, NULL, domain, type, protocol)
+
+#define SAFE_SOCKETPAIR(domain, type, protocol, sv) \
+ safe_socketpair(__FILE__, __LINE__, domain, type, protocol, sv)
+
+#define SAFE_GETSOCKOPT(fd, level, optname, optval, optlen) \
+ safe_getsockopt(__FILE__, __LINE__, fd, level, optname, optval, optlen)
+
+#define SAFE_SETSOCKOPT(fd, level, optname, optval, optlen) \
+ safe_setsockopt(__FILE__, __LINE__, fd, level, optname, optval, optlen)
+
+#define SAFE_SETSOCKOPT_INT(fd, l, n, val) \
+ do { \
+ int v = val; \
+ safe_setsockopt(__FILE__, __LINE__, fd, l, n, &v, sizeof(v)); \
+ } while (0)
+
+#define SAFE_SEND(strict, sockfd, buf, len, flags) \
+ safe_send(__FILE__, __LINE__, strict, sockfd, buf, len, flags)
+
+#define SAFE_SENDTO(strict, fd, buf, len, flags, dest_addr, addrlen) \
+ safe_sendto(__FILE__, __LINE__, strict, fd, buf, len, flags, \
+ dest_addr, addrlen)
+
+#define SAFE_SENDMSG(msg_len, fd, msg, flags) \
+ safe_sendmsg(__FILE__, __LINE__, msg_len, fd, msg, flags)
+
+#define SAFE_RECVMSG(msg_len, fd, msg, flags) \
+ safe_recvmsg(__FILE__, __LINE__, msg_len, fd, msg, flags)
+
+#define SAFE_BIND(socket, address, address_len) \
+ safe_bind(__FILE__, __LINE__, NULL, socket, address, \
+ address_len)
+
+#define SAFE_LISTEN(socket, backlog) \
+ safe_listen(__FILE__, __LINE__, NULL, socket, backlog)
+
+#define SAFE_ACCEPT(sockfd, addr, addrlen) \
+ safe_accept(__FILE__, __LINE__, NULL, sockfd, addr, addrlen)
+
+#define SAFE_CONNECT(sockfd, addr, addrlen) \
+ safe_connect(__FILE__, __LINE__, NULL, sockfd, addr, addrlen)
+
+#define SAFE_GETSOCKNAME(sockfd, addr, addrlen) \
+ safe_getsockname(__FILE__, __LINE__, NULL, sockfd, addr, \
+ addrlen)
+
+#define SAFE_GETHOSTNAME(name, size) \
+ safe_gethostname(__FILE__, __LINE__, name, size)
+
+#define TST_GETSOCKPORT(sockfd) \
+ tst_getsockport(__FILE__, __LINE__, sockfd)
+
+#define TST_GET_UNUSED_PORT(family, type) \
+ tst_get_unused_port(__FILE__, __LINE__, NULL, family, type)
+
+/* new API only */
+
+#define SAFE_GETADDRINFO(src_addr, port, hints, addr_info) \
+ safe_getaddrinfo(__FILE__, __LINE__, src_addr, port, hints, addr_info)
+
+#endif /* TST_SAFE_NET_H__ */
diff --git a/src/kernel/tests/include/tst_safe_posix_ipc.h b/src/kernel/tests/include/tst_safe_posix_ipc.h
new file mode 100644
index 0000000..d74ef4e
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_posix_ipc.h
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2017-2019 Petr Vorel pvorel@suse.cz
+ */
+
+#ifndef TST_SAFE_POSIX_IPC_H__
+#define TST_SAFE_POSIX_IPC_H__
+
+#include <mqueue.h>
+#include <stdarg.h>
+
+#define SAFE_MQ_OPEN(pathname, oflags, ...) \
+ safe_mq_open(__FILE__, __LINE__, (pathname), (oflags), ##__VA_ARGS__)
+
+static inline int safe_mq_open(const char *file, const int lineno,
+ const char *pathname, int oflags, ...)
+{
+ va_list ap;
+ int rval;
+ mode_t mode;
+ struct mq_attr *attr;
+
+ va_start(ap, oflags);
+
+ /* Android's NDK's mode_t is smaller than an int, which results in
+ * SIGILL here when passing the mode_t type.
+ */
+#ifndef __ANDROID__
+ mode = va_arg(ap, mode_t);
+#else
+ mode = va_arg(ap, int);
+#endif
+
+ attr = va_arg(ap, struct mq_attr *);
+
+ va_end(ap);
+
+ rval = mq_open(pathname, oflags, mode, attr);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO, "%s:%d: mq_open(%s,%d,0%o,%p) failed",
+ file, lineno, pathname, oflags, mode, attr);
+ }
+
+ return rval;
+}
+
+#endif /* TST_SAFE_POSIX_IPC_H__ */
diff --git a/src/kernel/tests/include/tst_safe_prw.h b/src/kernel/tests/include/tst_safe_prw.h
new file mode 100644
index 0000000..01a684d
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_prw.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2010-2017 Linux Test Project
+ */
+
+#ifndef TST_SAFE_PRW_H__
+#define TST_SAFE_PRW_H__
+
+static inline ssize_t safe_pread(const char *file, const int lineno,
+ char len_strict, int fildes, void *buf, size_t nbyte,
+ off_t offset)
+{
+ ssize_t rval;
+
+ rval = pread(fildes, buf, nbyte, offset);
+
+ if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "pread(%d,%p,%zu,%lld) failed",
+ fildes, buf, nbyte, (long long)offset);
+ }
+
+ return rval;
+}
+#define SAFE_PREAD(len_strict, fildes, buf, nbyte, offset) \
+ safe_pread(__FILE__, __LINE__, (len_strict), (fildes), \
+ (buf), (nbyte), (offset))
+
+static inline ssize_t safe_pwrite(const char *file, const int lineno,
+ char len_strict, int fildes, const void *buf, size_t nbyte,
+ off_t offset)
+{
+ ssize_t rval;
+
+ rval = pwrite(fildes, buf, nbyte, offset);
+ if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "pwrite(%d,%p,%zu,%lld) failed",
+ fildes, buf, nbyte, (long long)offset);
+ }
+
+ return rval;
+}
+#define SAFE_PWRITE(len_strict, fildes, buf, nbyte, offset) \
+ safe_pwrite(__FILE__, __LINE__, (len_strict), (fildes), \
+ (buf), (nbyte), (offset))
+
+#endif /* SAFE_PRW_H__ */
diff --git a/src/kernel/tests/include/tst_safe_pthread.h b/src/kernel/tests/include/tst_safe_pthread.h
new file mode 100644
index 0000000..0c6d4d2
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_pthread.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
+ */
+
+#ifndef TST_SAFE_PTHREAD_H__
+#define TST_SAFE_PTHREAD_H__
+
+/*
+ * Macro to use for making functions called only once in
+ * multi-threaded tests such as init or cleanup function.
+ * The first call to @name_fn function by any thread shall
+ * call the @exec_fn. Subsequent calls shall not call @exec_fn.
+ * *_fn functions must not take any arguments.
+ */
+#define TST_DECLARE_ONCE_FN(name_fn, exec_fn) \
+ void name_fn(void) \
+ { \
+ static pthread_once_t ltp_once = PTHREAD_ONCE_INIT; \
+ pthread_once(&ltp_once, exec_fn); \
+ }
+
+int safe_pthread_create(const char *file, const int lineno,
+ pthread_t *thread_id, const pthread_attr_t *attr,
+ void *(*thread_fn)(void *), void *arg);
+#define SAFE_PTHREAD_CREATE(thread_id, attr, thread_fn, arg) \
+ safe_pthread_create(__FILE__, __LINE__, thread_id, attr, thread_fn, arg)
+
+int safe_pthread_join(const char *file, const int lineno,
+ pthread_t thread_id, void **retval);
+#define SAFE_PTHREAD_JOIN(thread_id, retval) \
+ safe_pthread_join(__FILE__, __LINE__, thread_id, retval)
+
+#endif /* TST_SAFE_PTHREAD_H__ */
diff --git a/src/kernel/tests/include/tst_safe_stdio.h b/src/kernel/tests/include/tst_safe_stdio.h
new file mode 100644
index 0000000..e4bff34
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_stdio.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2013-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_SAFE_STDIO_H__
+#define TST_SAFE_STDIO_H__
+
+#include <stdio.h>
+
+#include "safe_stdio_fn.h"
+
+#define SAFE_FOPEN(path, mode) \
+ safe_fopen(__FILE__, __LINE__, NULL, path, mode)
+
+#define SAFE_FCLOSE(f) \
+ safe_fclose(__FILE__, __LINE__, NULL, f)
+
+#define SAFE_ASPRINTF(strp, fmt, ...) \
+ safe_asprintf(__FILE__, __LINE__, NULL, strp, fmt, __VA_ARGS__)
+
+#define SAFE_POPEN(command, type) \
+ safe_popen(__FILE__, __LINE__, NULL, command, type)
+
+#endif /* TST_SAFE_STDIO_H__ */
diff --git a/src/kernel/tests/include/tst_safe_sysv_ipc.h b/src/kernel/tests/include/tst_safe_sysv_ipc.h
new file mode 100644
index 0000000..3e0e50e
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_sysv_ipc.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2017 Xiao yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#ifndef TST_SAFE_SYSV_IPC_H__
+#define TST_SAFE_SYSV_IPC_H__
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+
+int safe_msgget(const char *file, const int lineno, key_t key, int msgflg);
+#define SAFE_MSGGET(key, msgflg) \
+ safe_msgget(__FILE__, __LINE__, (key), (msgflg))
+
+int safe_msgsnd(const char *file, const int lineno, int msqid, const void *msgp,
+ size_t msgsz, int msgflg);
+#define SAFE_MSGSND(msqid, msgp, msgsz, msgflg) \
+ safe_msgsnd(__FILE__, __LINE__, (msqid), (msgp), (msgsz), (msgflg))
+
+ssize_t safe_msgrcv(const char *file, const int lineno, int msqid, void *msgp,
+ size_t msgsz, long msgtyp, int msgflg);
+#define SAFE_MSGRCV(msqid, msgp, msgsz, msgtyp, msgflg) \
+ safe_msgrcv(__FILE__, __LINE__, (msqid), (msgp), (msgsz), (msgtyp), (msgflg))
+
+int safe_msgctl(const char *file, const int lineno, int msqid, int cmd,
+ struct msqid_ds *buf);
+#define SAFE_MSGCTL(msqid, cmd, buf) ({ \
+ int tst_ret_ = safe_msgctl(__FILE__, __LINE__, (msqid), (cmd), (buf)); \
+ (msqid) = ((cmd) == IPC_RMID ? -1 : (msqid)); \
+ tst_ret_;})
+
+int safe_shmget(const char *file, const int lineno, key_t key, size_t size,
+ int shmflg);
+#define SAFE_SHMGET(key, size, shmflg) \
+ safe_shmget(__FILE__, __LINE__, (key), (size), (shmflg))
+
+void *safe_shmat(const char *file, const int lineno, int shmid,
+ const void *shmaddr, int shmflg);
+#define SAFE_SHMAT(shmid, shmaddr, shmflg) \
+ safe_shmat(__FILE__, __LINE__, (shmid), (shmaddr), (shmflg))
+
+int safe_shmdt(const char *file, const int lineno, const void *shmaddr);
+#define SAFE_SHMDT(shmaddr) safe_shmdt(__FILE__, __LINE__, (shmaddr))
+
+int safe_shmctl(const char *file, const int lineno, int shmid, int cmd,
+ struct shmid_ds *buf);
+#define SAFE_SHMCTL(shmid, cmd, buf) ({ \
+ int tst_ret_ = safe_shmctl(__FILE__, __LINE__, (shmid), (cmd), (buf)); \
+ (shmid) = ((cmd) == IPC_RMID ? -1 : (shmid)); \
+ tst_ret_;})
+
+#endif /* TST_SAFE_SYSV_IPC_H__ */
diff --git a/src/kernel/tests/include/tst_safe_timerfd.h b/src/kernel/tests/include/tst_safe_timerfd.h
new file mode 100644
index 0000000..526f128
--- /dev/null
+++ b/src/kernel/tests/include/tst_safe_timerfd.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ */
+
+#ifndef TST_SAFE_TIMERFD_H__
+#define TST_SAFE_TIMERFD_H__
+
+#include "lapi/timerfd.h"
+
+int safe_timerfd_create(const char *file, const int lineno,
+ int clockid, int flags);
+
+#define SAFE_TIMERFD_CREATE(clockid, flags)\
+ safe_timerfd_create(__FILE__, __LINE__, (clockid), (flags))
+
+int safe_timerfd_gettime(const char *file, const int lineno,
+ int fd, struct itimerspec *curr_value);
+
+#define SAFE_TIMERFD_GETTIME(fd, curr_value)\
+ safe_timerfd_gettime(__FILE__, __LINE__, (fd), (curr_value))
+
+int safe_timerfd_settime(const char *file, const int lineno,
+ int fd, int flags,
+ const struct itimerspec *new_value,
+ struct itimerspec *old_value);
+
+#define SAFE_TIMERFD_SETTIME(fd, flags, new_value, old_value)\
+ safe_timerfd_settime(__FILE__, __LINE__, (fd), (flags), (new_value), \
+ (old_value))
+
+#endif /* SAFE_TIMERFD_H__ */
diff --git a/src/kernel/tests/include/tst_sig_proc.h b/src/kernel/tests/include/tst_sig_proc.h
new file mode 100644
index 0000000..b85981e
--- /dev/null
+++ b/src/kernel/tests/include/tst_sig_proc.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2016 Linux Test Project
+ */
+
+#ifndef TST_SIG_PROC_H__
+#define TST_SIG_PROC_H__
+
+#include <sys/types.h>
+
+pid_t create_sig_proc(int sig, int count, unsigned int usec);
+
+#endif /* TST_SIG_PROC_H__ */
diff --git a/src/kernel/tests/include/tst_sys_conf.h b/src/kernel/tests/include/tst_sys_conf.h
new file mode 100644
index 0000000..323e29a
--- /dev/null
+++ b/src/kernel/tests/include/tst_sys_conf.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2018 Jan Stancek <jstancek@redhat.com>
+ */
+
+#ifndef TST_SYS_CONF_H__
+#define TST_SYS_CONF_H__
+
+struct tst_sys_conf {
+ char path[PATH_MAX];
+ char value[PATH_MAX];
+ struct tst_sys_conf *next;
+};
+
+int tst_sys_conf_save_str(const char *path, const char *value);
+int tst_sys_conf_save(const char *path);
+void tst_sys_conf_restore(int verbose);
+void tst_sys_conf_dump(void);
+
+#endif
diff --git a/src/kernel/tests/include/tst_taint.h b/src/kernel/tests/include/tst_taint.h
new file mode 100644
index 0000000..bd8076c
--- /dev/null
+++ b/src/kernel/tests/include/tst_taint.h
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Michael Moese <mmoese@suse.de>
+ */
+
+/* Usage example
+ *
+ * ...
+ * #include "tst_test.h"
+ * ..
+ * static struct tst_test test = {
+ * ...
+ * .taint_check = TST_TAINT_W | TST_TAINT_D,
+ * ...
+ * };
+ *
+ * void run(void)
+ * {
+ * ...
+ * . test code here
+ * ...
+ * if (tst_taint_check() != 0)
+ * tst_res(TFAIL, "kernel has issues");
+ * else
+ * tst_res(TPASS, "kernel seems to be fine");
+ * }
+ *
+ *
+ *
+ * The above code checks whether the kernel issued a warning (TST_TAINT_W)
+ * or even died (TST_TAINT_D) during test execution.
+ * If these are set after running a test case, we most likely
+ * triggered a kernel bug.
+ *
+ * You do not need to use tst_taint_check() explicitly because it'll be called
+ * automatically at the end of testing by the LTP library if
+ * tst_test.taint_check in non-zero.
+ */
+
+#ifndef TST_TAINTED_H__
+#define TST_TAINTED_H__
+
+/*
+ * This are all 17 flags that are present in kernel 4.15
+ * see kernel/panic.c in kernel sources
+ *
+ * Not all of them are valid in all kernel versions.
+ */
+#define TST_TAINT_G (1 << 0) /* a module with non-GPL license loaded */
+#define TST_TAINT_F (1 << 1) /* a module was force-loaded */
+#define TST_TAINT_S (1 << 2) /* SMP with Non-SMP kernel */
+#define TST_TAINT_R (1 << 3) /* module force unloaded */
+#define TST_TAINT_M (1 << 4) /* machine check error occurred */
+#define TST_TAINT_B (1 << 5) /* page-release function found bad page */
+#define TST_TAINT_U (1 << 6) /* user requested taint flag */
+#define TST_TAINT_D (1 << 7) /* kernel died recently - OOPS or BUG */
+#define TST_TAINT_A (1 << 8) /* ACPI table has been overwritten */
+#define TST_TAINT_W (1 << 9) /* a warning has been issued by kernel */
+#define TST_TAINT_C (1 << 10) /* driver from drivers/staging was loaded */
+#define TST_TAINT_I (1 << 11) /* working around BIOS/Firmware bug */
+#define TST_TAINT_O (1 << 12) /* out of tree module loaded */
+#define TST_TAINT_E (1 << 13) /* unsigned module was loaded */
+#define TST_TAINT_L (1 << 14) /* A soft lock-up has previously occurred */
+#define TST_TAINT_K (1 << 15) /* kernel has been live-patched */
+#define TST_TAINT_X (1 << 16) /* auxiliary taint, for distro's use */
+#define TST_TAINT_T (1 << 17) /* kernel was built with the struct randomization plugin */
+
+/*
+ * Initialize and prepare support for checking tainted kernel. Called
+ * automatically by LTP library during test setup if tst_test.taint_check
+ * is non-zero. The value of tst_test.taint_check will be passed as the mask
+ * argument.
+ *
+ * supply the mask of TAINT-flags you want to check, for example
+ * (TST_TAINT_W | TST_TAINT_D) when you want to check if the kernel issued
+ * a warning or even reported it died.
+ *
+ * This function tests if the requested flags are supported on the
+ * locally running kernel. In case the tainted-flags are already set by
+ * the kernel, there is no reason to continue and TBROK is generated.
+ *
+ * The mask must not be zero.
+ */
+void tst_taint_init(unsigned int mask);
+
+
+/*
+ * check if the tainted flags handed to tst_taint_init() are still not set
+ * during or after running the test.
+ * Calling this function is only allowed after tst_taint_init() was called,
+ * otherwise TBROK will be generated.
+ *
+ * returns 0 or a bitmask of the flags that currently tainted the kernel.
+ */
+unsigned int tst_taint_check(void);
+
+
+#endif /* TST_TAINTED_H__ */
diff --git a/src/kernel/tests/include/tst_test.h b/src/kernel/tests/include/tst_test.h
new file mode 100644
index 0000000..c91d3f1
--- /dev/null
+++ b/src/kernel/tests/include/tst_test.h
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ * Copyright (c) Linux Test Project, 2016-2019
+ */
+
+#ifndef TST_TEST_H__
+#define TST_TEST_H__
+
+#ifdef __TEST_H__
+# error Oldlib test.h already included
+#endif /* __TEST_H__ */
+
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+
+#include "tst_common.h"
+#include "tst_res_flags.h"
+#include "tst_checkpoint.h"
+#include "tst_device.h"
+#include "tst_mkfs.h"
+#include "tst_fs.h"
+#include "tst_pid.h"
+#include "tst_cmd.h"
+#include "tst_cpu.h"
+#include "tst_process_state.h"
+#include "tst_atomic.h"
+#include "tst_kvercmp.h"
+#include "tst_clone.h"
+#include "tst_kernel.h"
+#include "tst_minmax.h"
+#include "tst_get_bad_addr.h"
+#include "tst_path_has_mnt_flags.h"
+#include "tst_sys_conf.h"
+#include "tst_coredump.h"
+#include "tst_buffers.h"
+#include "tst_capability.h"
+#include "tst_hugepage.h"
+#include "tst_assert.h"
+#include "tst_cgroup.h"
+#include "tst_lockdown.h"
+#include "tst_taint.h"
+
+/*
+ * Reports testcase result.
+ */
+void tst_res_(const char *file, const int lineno, int ttype,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+#define tst_res(ttype, arg_fmt, ...) \
+ ({ \
+ TST_RES_SUPPORTS_TCONF_TFAIL_TINFO_TPASS_TWARN(!((TTYPE_RESULT(ttype) ?: TCONF) & \
+ (TCONF | TFAIL | TINFO | TPASS | TWARN))); \
+ tst_res_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\
+ })
+
+void tst_resm_hexd_(const char *file, const int lineno, int ttype,
+ const void *buf, size_t size, const char *arg_fmt, ...)
+ __attribute__ ((format (printf, 6, 7)));
+
+#define tst_res_hexd(ttype, buf, size, arg_fmt, ...) \
+ tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \
+ (arg_fmt), ##__VA_ARGS__)
+
+/*
+ * Reports result and exits a test.
+ */
+void tst_brk_(const char *file, const int lineno, int ttype,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+#define tst_brk(ttype, arg_fmt, ...) \
+ ({ \
+ TST_BRK_SUPPORTS_ONLY_TCONF_TBROK(!((ttype) & \
+ (TBROK | TCONF | TFAIL))); \
+ tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\
+ })
+
+/* flush stderr and stdout */
+void tst_flush(void);
+
+pid_t safe_fork(const char *filename, unsigned int lineno);
+#define SAFE_FORK() \
+ safe_fork(__FILE__, __LINE__)
+
+#define TST_TRACE(expr) \
+ ({int ret = expr; \
+ ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \
+
+#include "tst_safe_macros.h"
+#include "tst_safe_file_ops.h"
+#include "tst_safe_net.h"
+
+/*
+ * Wait for all children and exit with TBROK if
+ * any of them returned a non-zero exit status.
+ */
+void tst_reap_children(void);
+
+struct tst_option {
+ char *optstr;
+ char **arg;
+ char *help;
+};
+
+/*
+ * Options parsing helpers.
+ *
+ * If str is NULL these are No-op.
+ *
+ * On failure non-zero (errno) is returned.
+ */
+int tst_parse_int(const char *str, int *val, int min, int max);
+int tst_parse_long(const char *str, long *val, long min, long max);
+int tst_parse_float(const char *str, float *val, float min, float max);
+
+struct tst_tag {
+ const char *name;
+ const char *value;
+};
+
+extern unsigned int tst_variant;
+
+struct tst_test {
+ /* number of tests available in test() function */
+ unsigned int tcnt;
+
+ struct tst_option *options;
+
+ const char *min_kver;
+
+ /* If set the test is compiled out */
+ const char *tconf_msg;
+
+ int needs_tmpdir:1;
+ int needs_root:1;
+ int forks_child:1;
+ int needs_device:1;
+ int needs_checkpoints:1;
+ int needs_overlay:1;
+ int format_device:1;
+ int mount_device:1;
+ int needs_rofs:1;
+ int child_needs_reinit:1;
+ int needs_devfs:1;
+ int restore_wallclock:1;
+ /*
+ * If set the test function will be executed for all available
+ * filesystems and the current filesytem type would be set in the
+ * tst_device->fs_type.
+ *
+ * The test setup and cleanup are executed before/after __EACH__ call
+ * to the test function.
+ */
+ int all_filesystems:1;
+
+ /*
+ * If set non-zero number of request_hugepages, test will try to reserve the
+ * expected number of hugepage for testing in setup phase. If system does not
+ * have enough hpage for using, it will try the best to reserve 80% available
+ * number of hpages. With success test stores the reserved hugepage number in
+ * 'tst_hugepages. For the system without hugetlb supporting, variable
+ * 'tst_hugepages' will be set to 0.
+ *
+ * Also, we do cleanup and restore work for the hpages resetting automatically.
+ */
+ unsigned long request_hugepages;
+
+ /*
+ * If set to non-zero, call tst_taint_init(taint_check) during setup
+ * and check kernel taint at the end of the test. If all_filesystems
+ * is non-zero, taint check will be performed after each FS test and
+ * testing will be terminated by TBROK if taint is detected.
+ */
+ unsigned int taint_check;
+
+ /*
+ * If set non-zero denotes number of test variant, the test is executed
+ * variants times each time with tst_variant set to different number.
+ *
+ * This allows us to run the same test for different settings. The
+ * intended use is to test different syscall wrappers/variants but the
+ * API is generic and does not limit the usage in any way.
+ */
+ unsigned int test_variants;
+
+ /* Minimal device size in megabytes */
+ unsigned int dev_min_size;
+
+ /* Device filesystem type override NULL == default */
+ const char *dev_fs_type;
+ /* Flags to be passed to tst_get_supported_fs_types() */
+ int dev_fs_flags;
+
+ /* Options passed to SAFE_MKFS() when format_device is set */
+ const char *const *dev_fs_opts;
+ const char *const *dev_extra_opts;
+
+ /* Device mount options, used if mount_device is set */
+ const char *mntpoint;
+ unsigned int mnt_flags;
+ void *mnt_data;
+
+ /* override default timeout per test run, disabled == -1 */
+ int timeout;
+
+ void (*setup)(void);
+ void (*cleanup)(void);
+
+ void (*test)(unsigned int test_nr);
+ void (*test_all)(void);
+
+ /* Syscall name used by the timer measurement library */
+ const char *scall;
+
+ /* Sampling function for timer measurement testcases */
+ int (*sample)(int clk_id, long long usec);
+
+ /* NULL terminated array of resource file names */
+ const char *const *resource_files;
+
+ /* NULL terminated array of needed kernel drivers */
+ const char * const *needs_drivers;
+
+ /*
+ * NULL terminated array of (/proc, /sys) files to save
+ * before setup and restore after cleanup
+ */
+ const char * const *save_restore;
+
+ /*
+ * NULL terminated array of kernel config options required for the
+ * test.
+ */
+ const char *const *needs_kconfigs;
+
+ /*
+ * NULL-terminated array to be allocated buffers.
+ */
+ struct tst_buffers *bufs;
+
+ /*
+ * NULL-terminated array of capability settings
+ */
+ struct tst_cap *caps;
+
+ /*
+ * {NULL, NULL} terminated array of tags.
+ */
+ const struct tst_tag *tags;
+
+ /* NULL terminated array of required commands */
+ const char *const *needs_cmds;
+};
+
+/*
+ * Runs tests.
+ */
+void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
+ __attribute__ ((noreturn));
+
+/*
+ * Does library initialization for child processes started by exec()
+ *
+ * The LTP_IPC_PATH variable must be passed to the program environment.
+ */
+void tst_reinit(void);
+
+//TODO Clean?
+#define TEST(SCALL) \
+ do { \
+ errno = 0; \
+ TST_RET = SCALL; \
+ TST_ERR = errno; \
+ } while (0)
+
+#define TEST_VOID(SCALL) \
+ do { \
+ errno = 0; \
+ SCALL; \
+ TST_ERR = errno; \
+ } while (0)
+
+extern long TST_RET;
+extern int TST_ERR;
+
+extern void *TST_RET_PTR;
+
+#define TESTPTR(SCALL) \
+ do { \
+ errno = 0; \
+ TST_RET_PTR = (void*)SCALL; \
+ TST_ERR = errno; \
+ } while (0)
+
+/*
+ * Functions to convert ERRNO to its name and SIGNAL to its name.
+ */
+const char *tst_strerrno(int err);
+const char *tst_strsig(int sig);
+/*
+ * Returns string describing status as returned by wait().
+ *
+ * BEWARE: Not thread safe.
+ */
+const char *tst_strstatus(int status);
+
+unsigned int tst_timeout_remaining(void);
+unsigned int tst_multiply_timeout(unsigned int timeout);
+void tst_set_timeout(int timeout);
+
+
+/*
+ * Returns path to the test temporary directory in a newly allocated buffer.
+ */
+char *tst_get_tmpdir(void);
+
+#ifndef TST_NO_DEFAULT_MAIN
+
+static struct tst_test test;
+
+int main(int argc, char *argv[])
+{
+ tst_run_tcases(argc, argv, &test);
+}
+
+#endif /* TST_NO_DEFAULT_MAIN */
+
+#define TST_TEST_TCONF(message) \
+ static struct tst_test test = { .tconf_msg = message } \
+
+#endif /* TST_TEST_H__ */
diff --git a/src/kernel/tests/include/tst_timer.h b/src/kernel/tests/include/tst_timer.h
new file mode 100644
index 0000000..d2c3f3c
--- /dev/null
+++ b/src/kernel/tests/include/tst_timer.h
@@ -0,0 +1,1055 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2015-2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+ /*
+
+ Timer - struct timespec conversion runtimes and easy to use functions to
+ measure elapsed time.
+
+ */
+
+#ifndef TST_TIMER
+#define TST_TIMER
+
+#include <sched.h>
+#include <sys/time.h>
+#include <mqueue.h>
+#include <time.h>
+#include "tst_test.h"
+#include "lapi/common_timers.h"
+#include "lapi/posix_types.h"
+#include "lapi/syscalls.h"
+
+/*
+ * Converts timeval to microseconds.
+ */
+static inline long long tst_timeval_to_us(struct timeval t)
+{
+ return t.tv_sec * 1000000 + t.tv_usec;
+}
+
+/*
+ * Converts timeval to milliseconds.
+ */
+static inline long long tst_timeval_to_ms(struct timeval t)
+{
+ return t.tv_sec * 1000 + (t.tv_usec + 500) / 1000;
+}
+
+/*
+ * Converts milliseconds to struct timeval
+ */
+static inline struct timeval tst_ms_to_timeval(long long ms)
+{
+ struct timeval ret;
+
+ ret.tv_sec = ms / 1000;
+ ret.tv_usec = (ms % 1000) * 1000;
+
+ return ret;
+}
+
+/*
+ * Converts microseconds to struct timeval
+ */
+static inline struct timeval tst_us_to_timeval(long long us)
+{
+ struct timeval ret;
+
+ ret.tv_sec = us / 1000000;
+ ret.tv_usec = us % 1000000;
+
+ return ret;
+}
+
+/*
+ * Returns difference between two timeval structures.
+ */
+static inline struct timeval tst_timeval_diff(struct timeval t1,
+ struct timeval t2)
+{
+ struct timeval res;
+
+ res.tv_sec = t1.tv_sec - t2.tv_sec;
+
+ if (t1.tv_usec < t2.tv_usec) {
+ res.tv_sec--;
+ res.tv_usec = 1000000 - (t2.tv_usec - t1.tv_usec);
+ } else {
+ res.tv_usec = t1.tv_usec - t2.tv_usec;
+ }
+
+ return res;
+}
+
+static inline long long tst_timeval_diff_us(struct timeval t1,
+ struct timeval t2)
+{
+ return tst_timeval_to_us(tst_timeval_diff(t1, t2));
+}
+
+static inline long long tst_timeval_diff_ms(struct timeval t1,
+ struct timeval t2)
+{
+ return tst_timeval_to_ms(tst_timeval_diff(t1, t2));
+}
+
+#ifndef __kernel_timespec
+
+typedef __kernel_long_t __kernel_old_time_t;
+
+struct __kernel_old_timeval {
+ __kernel_old_time_t tv_sec; /* seconds */
+ __kernel_suseconds_t tv_usec; /* microseconds */
+};
+
+struct __kernel_old_timespec {
+ __kernel_old_time_t tv_sec; /* seconds */
+ __kernel_old_time_t tv_nsec; /* nanoseconds */
+};
+
+typedef long long __kernel_time64_t;
+
+struct __kernel_timespec {
+ __kernel_time64_t tv_sec; /* seconds */
+ long long tv_nsec; /* nanoseconds */
+};
+
+struct __kernel_old_itimerspec {
+ struct __kernel_old_timespec it_interval; /* timer period */
+ struct __kernel_old_timespec it_value; /* timer expiration */
+};
+
+struct __kernel_itimerspec {
+ struct __kernel_timespec it_interval; /* timer period */
+ struct __kernel_timespec it_value; /* timer expiration */
+};
+#endif
+
+enum tst_ts_type {
+ TST_LIBC_TIMESPEC,
+ TST_KERN_OLD_TIMESPEC,
+ TST_KERN_TIMESPEC
+};
+
+struct tst_ts {
+ enum tst_ts_type type;
+ union ts {
+ struct timespec libc_ts;
+ struct __kernel_old_timespec kern_old_ts;
+ struct __kernel_timespec kern_ts;
+ } ts;
+};
+
+struct tst_its {
+ enum tst_ts_type type;
+ union {
+ struct __kernel_old_itimerspec kern_old_its;
+ struct __kernel_itimerspec kern_its;
+ } ts;
+};
+
+static inline void *tst_ts_get(struct tst_ts *t)
+{
+ if (!t)
+ return NULL;
+
+ switch (t->type) {
+ case TST_LIBC_TIMESPEC:
+ return &t->ts.libc_ts;
+ case TST_KERN_OLD_TIMESPEC:
+ return &t->ts.kern_old_ts;
+ case TST_KERN_TIMESPEC:
+ return &t->ts.kern_ts;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", t->type);
+ return NULL;
+ }
+}
+
+static inline void *tst_its_get(struct tst_its *t)
+{
+ if (!t)
+ return NULL;
+
+ switch (t->type) {
+ case TST_KERN_OLD_TIMESPEC:
+ return &t->ts.kern_old_its;
+ case TST_KERN_TIMESPEC:
+ return &t->ts.kern_its;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", t->type);
+ return NULL;
+ }
+}
+
+static inline int libc_clock_getres(clockid_t clk_id, void *ts)
+{
+ return clock_getres(clk_id, ts);
+}
+
+static inline int sys_clock_getres(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_getres, clk_id, ts);
+}
+
+static inline int sys_clock_getres64(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_getres_time64, clk_id, ts);
+}
+
+static inline int libc_clock_gettime(clockid_t clk_id, void *ts)
+{
+ return clock_gettime(clk_id, ts);
+}
+
+static inline int sys_clock_gettime(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_gettime, clk_id, ts);
+}
+
+static inline int sys_clock_gettime64(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_gettime64, clk_id, ts);
+}
+
+static inline int libc_clock_settime(clockid_t clk_id, void *ts)
+{
+ return clock_settime(clk_id, ts);
+}
+
+static inline int sys_clock_settime(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_settime, clk_id, ts);
+}
+
+static inline int sys_clock_settime64(clockid_t clk_id, void *ts)
+{
+ return tst_syscall(__NR_clock_settime64, clk_id, ts);
+}
+
+static inline int libc_clock_nanosleep(clockid_t clk_id, int flags,
+ void *request, void *remain)
+{
+ return clock_nanosleep(clk_id, flags, request, remain);
+}
+
+static inline int sys_clock_nanosleep(clockid_t clk_id, int flags,
+ void *request, void *remain)
+{
+ return tst_syscall(__NR_clock_nanosleep, clk_id, flags,
+ request, remain);
+}
+
+static inline int sys_clock_nanosleep64(clockid_t clk_id, int flags,
+ void *request, void *remain)
+{
+ return tst_syscall(__NR_clock_nanosleep_time64, clk_id, flags,
+ request, remain);
+}
+
+static inline int sys_futex(int *uaddr, int futex_op, int val, void *to,
+ int *uaddr2, int val3)
+{
+ return tst_syscall(__NR_futex, uaddr, futex_op, val, to, uaddr2, val3);
+}
+
+static inline int sys_futex_time64(int *uaddr, int futex_op, int val, void *to,
+ int *uaddr2, int val3)
+{
+ return tst_syscall(__NR_futex_time64, uaddr, futex_op, val, to, uaddr2, val3);
+}
+
+static inline int libc_mq_timedsend(mqd_t mqdes, const char *msg_ptr,
+ size_t msg_len, unsigned int msg_prio, void *abs_timeout)
+{
+ return mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
+}
+
+static inline int sys_mq_timedsend(mqd_t mqdes, const char *msg_ptr,
+ size_t msg_len, unsigned int msg_prio, void *abs_timeout)
+{
+ return tst_syscall(__NR_mq_timedsend, mqdes, msg_ptr, msg_len, msg_prio,
+ abs_timeout);
+}
+
+static inline int sys_mq_timedsend64(mqd_t mqdes, const char *msg_ptr,
+ size_t msg_len, unsigned int msg_prio, void *abs_timeout)
+{
+ return tst_syscall(__NR_mq_timedsend_time64, mqdes, msg_ptr, msg_len,
+ msg_prio, abs_timeout);
+}
+
+static inline ssize_t libc_mq_timedreceive(mqd_t mqdes, char *msg_ptr,
+ size_t msg_len, unsigned int *msg_prio, void *abs_timeout)
+{
+ return mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
+}
+
+static inline ssize_t sys_mq_timedreceive(mqd_t mqdes, char *msg_ptr,
+ size_t msg_len, unsigned int *msg_prio, void *abs_timeout)
+{
+ return tst_syscall(__NR_mq_timedreceive, mqdes, msg_ptr, msg_len,
+ msg_prio, abs_timeout);
+}
+
+static inline ssize_t sys_mq_timedreceive64(mqd_t mqdes, char *msg_ptr,
+ size_t msg_len, unsigned int *msg_prio, void *abs_timeout)
+{
+ return tst_syscall(__NR_mq_timedreceive_time64, mqdes, msg_ptr, msg_len,
+ msg_prio, abs_timeout);
+}
+
+static inline int libc_sched_rr_get_interval(pid_t pid, void *ts)
+{
+ return sched_rr_get_interval(pid, ts);
+}
+
+static inline int sys_sched_rr_get_interval(pid_t pid, void *ts)
+{
+ return tst_syscall(__NR_sched_rr_get_interval, pid, ts);
+}
+
+static inline int sys_sched_rr_get_interval64(pid_t pid, void *ts)
+{
+ return tst_syscall(__NR_sched_rr_get_interval_time64, pid, ts);
+}
+
+static inline int sys_timer_gettime(kernel_timer_t timerid, void *its)
+{
+ return tst_syscall(__NR_timer_gettime, timerid, its);
+}
+
+static inline int sys_timer_gettime64(kernel_timer_t timerid, void *its)
+{
+ return tst_syscall(__NR_timer_gettime64, timerid, its);
+}
+
+static inline int sys_timer_settime(kernel_timer_t timerid, int flags, void *its,
+ void *old_its)
+{
+ return tst_syscall(__NR_timer_settime, timerid, flags, its, old_its);
+}
+
+static inline int sys_timer_settime64(kernel_timer_t timerid, int flags, void *its,
+ void *old_its)
+{
+ return tst_syscall(__NR_timer_settime64, timerid, flags, its, old_its);
+}
+
+static inline int sys_timerfd_gettime(int fd, void *its)
+{
+ return tst_syscall(__NR_timerfd_gettime, fd, its);
+}
+
+static inline int sys_timerfd_gettime64(int fd, void *its)
+{
+ return tst_syscall(__NR_timerfd_gettime64, fd, its);
+}
+
+static inline int sys_timerfd_settime(int fd, int flags, void *its,
+ void *old_its)
+{
+ return tst_syscall(__NR_timerfd_settime, fd, flags, its, old_its);
+}
+
+static inline int sys_timerfd_settime64(int fd, int flags, void *its,
+ void *old_its)
+{
+ return tst_syscall(__NR_timerfd_settime64, fd, flags, its, old_its);
+}
+
+/*
+ * Returns tst_ts seconds.
+ */
+static inline long long tst_ts_get_sec(struct tst_ts ts)
+{
+ switch (ts.type) {
+ case TST_LIBC_TIMESPEC:
+ return ts.ts.libc_ts.tv_sec;
+ case TST_KERN_OLD_TIMESPEC:
+ return ts.ts.kern_old_ts.tv_sec;
+ case TST_KERN_TIMESPEC:
+ return ts.ts.kern_ts.tv_sec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", ts.type);
+ return -1;
+ }
+}
+
+/*
+ * Returns tst_ts nanoseconds.
+ */
+static inline long long tst_ts_get_nsec(struct tst_ts ts)
+{
+ switch (ts.type) {
+ case TST_LIBC_TIMESPEC:
+ return ts.ts.libc_ts.tv_nsec;
+ case TST_KERN_OLD_TIMESPEC:
+ return ts.ts.kern_old_ts.tv_nsec;
+ case TST_KERN_TIMESPEC:
+ return ts.ts.kern_ts.tv_nsec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", ts.type);
+ return -1;
+ }
+}
+
+/*
+ * Sets tst_ts seconds.
+ */
+static inline void tst_ts_set_sec(struct tst_ts *ts, long long sec)
+{
+ switch (ts->type) {
+ case TST_LIBC_TIMESPEC:
+ ts->ts.libc_ts.tv_sec = sec;
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ ts->ts.kern_old_ts.tv_sec = sec;
+ break;
+ case TST_KERN_TIMESPEC:
+ ts->ts.kern_ts.tv_sec = sec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", ts->type);
+ }
+}
+
+/*
+ * Sets tst_ts nanoseconds.
+ */
+static inline void tst_ts_set_nsec(struct tst_ts *ts, long long nsec)
+{
+ switch (ts->type) {
+ case TST_LIBC_TIMESPEC:
+ ts->ts.libc_ts.tv_nsec = nsec;
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ ts->ts.kern_old_ts.tv_nsec = nsec;
+ break;
+ case TST_KERN_TIMESPEC:
+ ts->ts.kern_ts.tv_nsec = nsec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", ts->type);
+ }
+}
+
+/*
+ * Returns tst_its it_interval seconds.
+ */
+static inline long long tst_its_get_interval_sec(struct tst_its its)
+{
+ switch (its.type) {
+ case TST_KERN_OLD_TIMESPEC:
+ return its.ts.kern_old_its.it_interval.tv_sec;
+ case TST_KERN_TIMESPEC:
+ return its.ts.kern_its.it_interval.tv_sec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its.type);
+ return -1;
+ }
+}
+
+/*
+ * Returns tst_its it_interval nanoseconds.
+ */
+static inline long long tst_its_get_interval_nsec(struct tst_its its)
+{
+ switch (its.type) {
+ case TST_KERN_OLD_TIMESPEC:
+ return its.ts.kern_old_its.it_interval.tv_nsec;
+ case TST_KERN_TIMESPEC:
+ return its.ts.kern_its.it_interval.tv_nsec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its.type);
+ return -1;
+ }
+}
+
+/*
+ * Sets tst_its it_interval seconds.
+ */
+static inline void tst_its_set_interval_sec(struct tst_its *its, long long sec)
+{
+ switch (its->type) {
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ its->ts.kern_old_its.it_interval.tv_sec = sec;
+ break;
+ case TST_KERN_TIMESPEC:
+ its->ts.kern_its.it_interval.tv_sec = sec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its->type);
+ }
+}
+
+/*
+ * Sets tst_its it_interval nanoseconds.
+ */
+static inline void tst_its_set_interval_nsec(struct tst_its *its, long long nsec)
+{
+ switch (its->type) {
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ its->ts.kern_old_its.it_interval.tv_nsec = nsec;
+ break;
+ case TST_KERN_TIMESPEC:
+ its->ts.kern_its.it_interval.tv_nsec = nsec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its->type);
+ }
+}
+
+/*
+ * Returns tst_its it_value seconds.
+ */
+static inline long long tst_its_get_value_sec(struct tst_its its)
+{
+ switch (its.type) {
+ case TST_KERN_OLD_TIMESPEC:
+ return its.ts.kern_old_its.it_value.tv_sec;
+ case TST_KERN_TIMESPEC:
+ return its.ts.kern_its.it_value.tv_sec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its.type);
+ return -1;
+ }
+}
+
+/*
+ * Returns tst_its it_value nanoseconds.
+ */
+static inline long long tst_its_get_value_nsec(struct tst_its its)
+{
+ switch (its.type) {
+ case TST_KERN_OLD_TIMESPEC:
+ return its.ts.kern_old_its.it_value.tv_nsec;
+ case TST_KERN_TIMESPEC:
+ return its.ts.kern_its.it_value.tv_nsec;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its.type);
+ return -1;
+ }
+}
+
+/*
+ * Sets tst_its it_value seconds.
+ */
+static inline void tst_its_set_value_sec(struct tst_its *its, long long sec)
+{
+ switch (its->type) {
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ its->ts.kern_old_its.it_value.tv_sec = sec;
+ break;
+ case TST_KERN_TIMESPEC:
+ its->ts.kern_its.it_value.tv_sec = sec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its->type);
+ }
+}
+
+/*
+ * Sets tst_its it_value nanoseconds.
+ */
+static inline void tst_its_set_value_nsec(struct tst_its *its, long long nsec)
+{
+ switch (its->type) {
+ break;
+ case TST_KERN_OLD_TIMESPEC:
+ its->ts.kern_old_its.it_value.tv_nsec = nsec;
+ break;
+ case TST_KERN_TIMESPEC:
+ its->ts.kern_its.it_value.tv_nsec = nsec;
+ break;
+ default:
+ tst_brk(TBROK, "Invalid type: %d", its->type);
+ }
+}
+
+/*
+ * Checks that timespec is valid, i.e. that the timestamp is not zero and that
+ * the nanoseconds are normalized i.e. in <0, 1s) interval.
+ *
+ * 0: On success, i.e. timespec updated correctly.
+ * -1: Error, timespec not updated.
+ * -2: Error, tv_nsec is corrupted.
+ */
+static inline int tst_ts_valid(struct tst_ts *t)
+{
+ long long nsec = tst_ts_get_nsec(*t);
+
+ if (nsec < 0 || nsec >= 1000000000)
+ return -2;
+
+ if (tst_ts_get_sec(*t) == 0 && tst_ts_get_nsec(*t) == 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Converts timespec to tst_ts.
+ */
+static inline struct tst_ts tst_ts_from_timespec(struct timespec ts)
+{
+ struct tst_ts t = {
+ .type = TST_LIBC_TIMESPEC,
+ .ts.libc_ts.tv_sec = ts.tv_sec,
+ .ts.libc_ts.tv_nsec = ts.tv_nsec,
+ };
+
+ return t;
+}
+
+/*
+ * Converst tst_ts into timespec.
+ */
+static inline struct timespec tst_ts_to_timespec(struct tst_ts t)
+{
+ return t.ts.libc_ts;
+}
+
+/*
+ * Converts tst_ts to nanoseconds.
+ */
+static inline long long tst_ts_to_ns(struct tst_ts t)
+{
+ return tst_ts_get_sec(t) * 1000000000 + tst_ts_get_nsec(t);
+}
+
+/*
+ * Converts tst_ts to microseconds and rounds the value.
+ */
+static inline long long tst_ts_to_us(struct tst_ts t)
+{
+ return tst_ts_get_sec(t) * 1000000 +
+ (tst_ts_get_nsec(t) + 500) / 1000;
+}
+
+/*
+ * Converts timespec to microseconds and rounds the value.
+ */
+static inline long long tst_timespec_to_us(struct timespec ts)
+{
+ return tst_ts_to_us(tst_ts_from_timespec(ts));
+}
+
+/*
+ * Converts tst_ts to milliseconds and rounds the value.
+ */
+static inline long long tst_ts_to_ms(struct tst_ts t)
+{
+ return tst_ts_get_sec(t) * 1000 +
+ (tst_ts_get_nsec(t) + 500000) / 1000000;
+}
+
+/*
+ * Converts timespec to milliseconds and rounds the value.
+ */
+static inline long long tst_timespec_to_ms(struct timespec ts)
+{
+ return tst_ts_to_ms(tst_ts_from_timespec(ts));
+}
+
+/*
+ * Converts nanoseconds to tst_ts
+ */
+static inline struct tst_ts
+tst_ts_from_ns(enum tst_ts_type type, long long ns)
+{
+ struct tst_ts ret = {.type = type};
+
+ tst_ts_set_sec(&ret, ns / 1000000000);
+ tst_ts_set_nsec(&ret, ns % 1000000000);
+
+ return ret;
+}
+
+/*
+ * Converts microseconds to tst_ts
+ */
+static inline struct tst_ts
+tst_ts_from_us(enum tst_ts_type type, long long us)
+{
+ struct tst_ts ret = {.type = type};
+
+ tst_ts_set_sec(&ret, us / 1000000);
+ tst_ts_set_nsec(&ret, (us % 1000000) * 1000);
+
+ return ret;
+}
+
+/*
+ * Converts microseconds to timespec
+ */
+static inline struct timespec
+tst_timespec_from_us(long long us)
+{
+ return tst_ts_to_timespec(tst_ts_from_us(TST_LIBC_TIMESPEC, us));
+}
+
+/*
+ * Converts miliseconds to tst_ts
+ */
+static inline struct tst_ts
+tst_ts_from_ms(enum tst_ts_type type, long long ms)
+{
+ struct tst_ts ret = {.type = type};
+
+ tst_ts_set_sec(&ret, ms / 1000);
+ tst_ts_set_nsec(&ret, (ms % 1000) * 1000000);
+
+ return ret;
+}
+
+/*
+ * Converts miliseconds to timespec
+ */
+static inline struct timespec
+tst_timespec_from_ms(long long ms)
+{
+ return tst_ts_to_timespec(tst_ts_from_ms(TST_LIBC_TIMESPEC, ms));
+}
+
+/*
+ * Sets tst_its it_value from microseconds.
+ */
+static inline void tst_its_set_interval_from_us(struct tst_its *its, long long usec)
+{
+ struct timespec tp = tst_timespec_from_us(usec);
+
+ tst_its_set_interval_sec(its, tp.tv_sec);
+ tst_its_set_interval_nsec(its, tp.tv_nsec);
+}
+
+/*
+ * Sets tst_its it_value from microseconds.
+ */
+static inline void tst_its_set_value_from_us(struct tst_its *its, long long usec)
+{
+ struct timespec tp = tst_timespec_from_us(usec);
+
+ tst_its_set_value_sec(its, tp.tv_sec);
+ tst_its_set_value_nsec(its, tp.tv_nsec);
+}
+
+/*
+ * Sets tst_its it_interval from tst_ts.
+ */
+static inline void tst_its_set_interval_from_ts(struct tst_its *its, struct tst_ts ts)
+{
+ tst_its_set_interval_sec(its, tst_ts_get_sec(ts));
+ tst_its_set_interval_nsec(its, tst_ts_get_nsec(ts));
+}
+
+/*
+ * Sets tst_its it_value from tst_ts.
+ */
+static inline void tst_its_set_value_from_ts(struct tst_its *its, struct tst_ts ts)
+{
+ tst_its_set_value_sec(its, tst_ts_get_sec(ts));
+ tst_its_set_value_nsec(its, tst_ts_get_nsec(ts));
+}
+
+/*
+ * Returns if t1 less than t2. Both t1 and t2 must be normalized.
+ */
+static inline int tst_ts_lt(struct tst_ts t1, struct tst_ts t2)
+{
+ if (tst_ts_get_sec(t1) == tst_ts_get_sec(t2))
+ return tst_ts_get_nsec(t1) < tst_ts_get_nsec(t2);
+
+ return tst_ts_get_sec(t1) < tst_ts_get_sec(t2);
+}
+
+/*
+ * Returns if ts1 less than ts2. Both ts1 and ts2 must be normalized.
+ */
+static inline int tst_timespec_lt(struct timespec ts1, struct timespec ts2)
+{
+ return tst_ts_lt(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+}
+
+/*
+ * Returns normalized tst_ts, i.e. 0 <= nsec < 1000000000.
+ */
+static inline struct tst_ts tst_ts_normalize(struct tst_ts t)
+{
+ long long sec = tst_ts_get_sec(t);
+ long long nsec = tst_ts_get_nsec(t);
+
+ if (nsec >= 1000000000) {
+ tst_ts_set_sec(&t, sec + 1);
+ tst_ts_set_nsec(&t, nsec - 1000000000);
+ }
+
+ if (nsec < 0) {
+ tst_ts_set_sec(&t, sec - 1);
+ tst_ts_set_nsec(&t, nsec + 1000000000);
+ }
+
+ return t;
+}
+
+/*
+ * Adds us microseconds to tst_ts.
+ */
+static inline struct tst_ts
+tst_ts_add_us(struct tst_ts t, long long us)
+{
+ struct tst_ts res = {.type = t.type};
+
+ tst_ts_set_sec(&res, tst_ts_get_sec(t) + us / 1000000);
+ tst_ts_set_nsec(&res, tst_ts_get_nsec(t) + (us % 1000000) * 1000);
+
+ return tst_ts_normalize(res);
+}
+
+/*
+ * Adds us microseconds to struct timespec.
+ */
+static inline struct timespec
+tst_timespec_add_us(struct timespec ts, long long us)
+{
+ struct tst_ts res;
+
+ res = tst_ts_add_us(tst_ts_from_timespec(ts), us);
+
+ return tst_ts_to_timespec(res);
+}
+
+/*
+ * Substracts us microseconds from tst_ts.
+ */
+static inline struct tst_ts
+tst_ts_sub_us(struct tst_ts t, long long us)
+{
+ struct tst_ts res = {.type = t.type};
+
+ tst_ts_set_sec(&res, tst_ts_get_sec(t) - us / 1000000);
+ tst_ts_set_nsec(&res, tst_ts_get_nsec(t) - (us % 1000000) * 1000);
+
+ return tst_ts_normalize(res);
+}
+
+/*
+ * Substracts us microseconds from timespec.
+ */
+static inline struct timespec
+tst_timespec_sub_us(struct timespec ts, long long us)
+{
+ struct tst_ts res;
+
+ res = tst_ts_sub_us(tst_ts_from_timespec(ts), us);
+
+ return tst_ts_to_timespec(res);
+}
+
+/*
+ * Adds two tst_ts structures.
+ */
+static inline struct tst_ts
+tst_ts_add(struct tst_ts t1, struct tst_ts t2)
+{
+ struct tst_ts res = {.type = t1.type};
+
+ tst_ts_set_sec(&res, tst_ts_get_sec(t1) + tst_ts_get_sec(t2));
+ tst_ts_set_nsec(&res, tst_ts_get_nsec(t1) + tst_ts_get_nsec(t2));
+
+ return tst_ts_normalize(res);
+}
+
+/*
+ * Adds two timespec structures.
+ */
+static inline struct timespec
+tst_timespec_add(struct timespec ts1, struct timespec ts2)
+{
+ struct tst_ts res;
+
+ res = tst_ts_add(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+
+ return tst_ts_to_timespec(res);
+}
+
+/*
+ * Substract two tst_ts structures.
+ */
+static inline struct tst_ts
+tst_ts_diff(struct tst_ts t1, struct tst_ts t2)
+{
+ struct tst_ts res = {.type = t1.type};
+
+ tst_ts_set_sec(&res, tst_ts_get_sec(t1) - tst_ts_get_sec(t2));
+ tst_ts_set_nsec(&res, tst_ts_get_nsec(t1) - tst_ts_get_nsec(t2));
+
+ return tst_ts_normalize(res);
+}
+
+/*
+ * Substract two timespec structures.
+ */
+static inline struct timespec
+tst_timespec_diff(struct timespec ts1, struct timespec ts2)
+{
+ struct tst_ts res;
+
+ res = tst_ts_diff(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+
+ return tst_ts_to_timespec(res);
+}
+
+/*
+ * Substract two tst_ts structures returns number of nanoseconds.
+ */
+static inline long long
+tst_ts_diff_ns(struct tst_ts t1, struct tst_ts t2)
+{
+ return tst_ts_to_ns(tst_ts_diff(t1, t2));
+}
+
+/*
+ * Substract two timespec structures returns number of nanoseconds.
+ */
+static inline long long
+tst_timespec_diff_ns(struct timespec ts1, struct timespec ts2)
+{
+ return tst_ts_diff_ns(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+}
+
+/*
+ * Substract two tst_ts structures returns number of microseconds.
+ */
+static inline long long
+tst_ts_diff_us(struct tst_ts t1, struct tst_ts t2)
+{
+ return tst_ts_to_us(tst_ts_diff(t1, t2));
+}
+
+/*
+ * Substract two timespec structures returns number of microseconds.
+ */
+static inline long long
+tst_timespec_diff_us(struct timespec ts1, struct timespec ts2)
+{
+ return tst_ts_diff_us(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+}
+
+/*
+ * Substract two tst_ts structures returns number of milliseconds.
+ */
+static inline long long
+tst_ts_diff_ms(struct tst_ts t1, struct tst_ts t2)
+{
+ return tst_ts_to_ms(tst_ts_diff(t1, t2));
+}
+
+/*
+ * Substract two timespec structures returns number of milliseconds.
+ */
+static inline long long
+tst_timespec_diff_ms(struct timespec ts1, struct timespec ts2)
+{
+ return tst_ts_diff_ms(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+}
+
+/*
+ * Returns absolute value of difference between two timespec structures.
+ */
+static inline struct tst_ts
+tst_ts_abs_diff(struct tst_ts t1, struct tst_ts t2)
+{
+ if (tst_ts_lt(t1, t2))
+ return tst_ts_diff(t2, t1);
+ else
+ return tst_ts_diff(t1, t2);
+}
+
+/*
+ * Returns absolute value of difference between two tst_ts structures in
+ * microseconds.
+ */
+static inline long long
+tst_ts_abs_diff_us(struct tst_ts t1, struct tst_ts t2)
+{
+ return tst_ts_to_us(tst_ts_abs_diff(t1, t2));
+}
+
+/*
+ * Returns absolute value of difference between two timespec structures in
+ * microseconds.
+ */
+static inline long long
+tst_timespec_abs_diff_us(struct timespec ts1, struct timespec ts2)
+{
+ return tst_ts_abs_diff_us(tst_ts_from_timespec(ts1), tst_ts_from_timespec(ts2));
+}
+
+/*
+ * Returns absolute value of difference between two timespec structures in
+ * milliseconds.
+ */
+static inline long long
+tst_ts_abs_diff_ms(struct tst_ts t1, struct tst_ts t2)
+{
+ return tst_ts_to_ms(tst_ts_abs_diff(t1, t2));
+}
+
+/*
+ * Exits the test with TCONF if particular timer is not supported. This is
+ * intended to be used in test setup. There is no cleanup callback parameter as
+ * you are expected to call it before initializing any resources that has to be
+ * cleaned up later.
+ *
+ * @clk_id: Posix clock to use.
+ */
+void tst_timer_check(clockid_t clk_id);
+
+/*
+ * Marks a start time for given clock type.
+ *
+ * @clk_id: Posix clock to use.
+ */
+void tst_timer_start(clockid_t clk_id);
+
+/*
+ * Returns true if timer started by tst_timer_start() has been running for
+ * longer than ms seconds.
+ *
+ * @ms: Time interval in milliseconds.
+ */
+int tst_timer_expired_ms(long long ms);
+
+/*
+ * Marks timer end time.
+ */
+void tst_timer_stop(void);
+
+/*
+ * Retuns elapsed time in struct timespec.
+ */
+struct timespec tst_timer_elapsed(void);
+
+/*
+ * Returns elapsed time in milliseconds.
+ */
+static inline long long tst_timer_elapsed_ms(void)
+{
+ return tst_timespec_to_ms(tst_timer_elapsed());
+}
+
+/*
+ * Returns elapsed time in microseconds.
+ */
+static inline long long tst_timer_elapsed_us(void)
+{
+ return tst_timespec_to_us(tst_timer_elapsed());
+}
+
+#endif /* TST_TIMER */
diff --git a/src/kernel/tests/include/tst_timer_test.h b/src/kernel/tests/include/tst_timer_test.h
new file mode 100644
index 0000000..b825a4d
--- /dev/null
+++ b/src/kernel/tests/include/tst_timer_test.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+ /*
+
+ Timer measuring library.
+
+ The test is supposed to define sampling function and set it in the tst_test
+ structure the rest of the work is then done by the library.
+
+ int sample(int clk_id, long long usec)
+ {
+ // Any setup done here
+
+ tst_timer_start(clk_id);
+ // Call that is being measured sleeps for usec
+ tst_timer_stop();
+ tst_timer_sample();
+
+ // Any cleanup done here
+
+ // Non-zero return exits the test
+ }
+
+ struct tst_test test = {
+ .scall = "syscall_name()",
+ .sample = sample,
+ };
+
+ */
+
+#ifndef TST_TIMER_TEST__
+#define TST_TIMER_TEST__
+
+#include "tst_test.h"
+#include "tst_timer.h"
+
+void tst_timer_sample(void);
+
+# ifdef TST_NO_DEFAULT_MAIN
+struct tst_test *tst_timer_test_setup(struct tst_test *test);
+# endif /* TST_NO_DEFAULT_MAIN */
+#endif /* TST_TIMER_TEST__ */
diff --git a/src/kernel/tests/include/tst_uinput.h b/src/kernel/tests/include/tst_uinput.h
new file mode 100644
index 0000000..cf351cd
--- /dev/null
+++ b/src/kernel/tests/include/tst_uinput.h
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_UINPUT_H__
+#define TST_UINPUT_H__
+
+/**
+ * Tries to open the uinput device.
+ *
+ * Returns file descriptor on success, -1 on failure.
+ */
+int open_uinput(void);
+
+/**
+ * Creates virtual input device.
+ *
+ * @fd File descriptor returned by open_uinput().
+ */
+void create_input_device(int fd);
+
+/**
+ * Parses /proc/bus/input/devices and returns the strings for our virtual device.
+ * If passing 'H' to it, it returns HANDLERS string. If passing 'S' to it, it
+ * returns SYSFS string.
+ *
+ * Returns newly allocated string, or NULL in a case of failure.
+ */
+char *get_input_field_value(char field);
+
+/**
+ * Sets up the virtual device to appear as a mouse, this must be called before
+ * the call to create_input_device().
+ *
+ * @fd File descriptor as returned by open_uinput().
+ */
+void setup_mouse_events(int fd);
+
+/**
+ * Destroys virtual input device.
+ *
+ * @fd File descriptor returned by open_uinput().
+ */
+void destroy_input_device(int fd);
+
+#endif /* TST_UINPUT_H__ */
diff --git a/src/kernel/tests/include/tst_wallclock.h b/src/kernel/tests/include/tst_wallclock.h
new file mode 100644
index 0000000..7d6723a
--- /dev/null
+++ b/src/kernel/tests/include/tst_wallclock.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+
+#ifndef TST_WALLCLK_H__
+#define TST_WALLCLK_H__
+
+void tst_wallclock_save(void);
+
+void tst_wallclock_restore(void);
+
+#endif /* TST_WALLCLK_H__ */
diff --git a/src/kernel/tests/lib/CMakeLists.txt b/src/kernel/tests/lib/CMakeLists.txt
new file mode 100644
index 0000000..0ce8982
--- /dev/null
+++ b/src/kernel/tests/lib/CMakeLists.txt
@@ -0,0 +1,70 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(xloop-kernel-test-lib)
+
+add_library(libltp STATIC ${CMAKE_CURRENT_SOURCE_DIR}/cloner.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/get_path.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/parse_opts.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/random_range.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/safe_file_ops.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/safe_macros.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/safe_net.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/safe_pthread.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/safe_stdio.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/self_exec.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tlibio.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_af_alg.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_ansi_color.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_assert.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_buffers.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_capability.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_cgroup.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_checkpoint.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_checksum.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_clocks.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_cmd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_coredump.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_cpu.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_crypto.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_device.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_dir_is_empty.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fill_file.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fill_fs.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fs_has_free.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fs_link_count.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fs_setup.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_fs_type.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_get_bad_addr.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_hugepage.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_ioctl.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_kconfig.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_kernel.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_kvercmp.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_lockdown.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_memutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_mkfs.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_module.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_net.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_parse_opts.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_path_has_mnt_flags.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_pid.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_process_state.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_res.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_resource.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_safe_macros.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_safe_sysv_ipc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_safe_timerfd.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_sig.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_sig_proc.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_status.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_supported_fs_types.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_sys_conf.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_taint.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_test.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_timer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_timer_test.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_tmpdir.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_virt.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/tst_wallclock.c)
+target_include_directories(libltp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_compile_options(libltp PUBLIC "-Wno-deprecated-declarations")
diff --git a/src/kernel/tests/lib/cloner.c b/src/kernel/tests/lib/cloner.c
new file mode 100644
index 0000000..11401f2
--- /dev/null
+++ b/src/kernel/tests/lib/cloner.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2009
+ * Some wrappers for clone functionality. Thrown together by Serge Hallyn
+ * <serue@us.ibm.com> based on existing clone usage in ltp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <stdarg.h>
+#include "config.h"
+#include "tst_clone.h"
+
+#undef clone /* we want to use clone() */
+
+/*
+ * The ia64 port has never included a prototype for __clone2(). It was updated
+ * to take eight parameters in glibc commit:
+ *
+ * commit 625f22fc7f8e0d61e3e6cff2c65468b91dbad426
+ * Author: Ulrich Drepper <drepper@redhat.com>
+ * Date: Mon Mar 3 19:53:27 2003 +0000
+ *
+ * The first release that contained this commit was glibc-2.3.3 which is old
+ * enough to assume that __clone2() takes eight parameters.
+ */
+#if defined(__ia64__)
+extern int __clone2(int (*fn) (void *arg), void *child_stack_base,
+ size_t child_stack_size, int flags, void *arg,
+ pid_t *parent_tid, void *tls, pid_t *child_tid);
+#endif
+
+#ifndef CLONE_SUPPORTS_7_ARGS
+# define clone(fn, stack, flags, arg, ptid, tls, ctid) \
+ clone(fn, stack, flags, arg)
+#endif
+
+/*
+ * ltp_clone: wrapper for clone to hide the architecture dependencies.
+ * 1. hppa takes bottom of stack and no stacksize (stack grows up)
+ * 2. __ia64__ takes bottom of stack and uses clone2
+ * 3. all others take top of stack (stack grows down)
+ */
+static int
+ltp_clone_(unsigned long flags, int (*fn)(void *arg), void *arg,
+ size_t stack_size, void *stack, pid_t *ptid, void *tls, pid_t *ctid)
+{
+ int ret;
+
+#if defined(__ia64__)
+ ret = __clone2(fn, stack, stack_size, flags, arg, ptid, tls, ctid);
+#else
+# if defined(__hppa__) || defined(__metag__)
+ /*
+ * These arches grow their stack up, so don't need to adjust the base.
+ * XXX: This should be made into a runtime test.
+ */
+# else
+ /*
+ * For archs where stack grows downwards, stack points to the topmost
+ * address of the memory space set up for the child stack.
+ */
+ if (stack)
+ stack += stack_size;
+# endif
+
+ ret = clone(fn, stack, flags, arg, ptid, tls, ctid);
+#endif
+
+ return ret;
+}
+
+int ltp_clone(unsigned long flags, int (*fn)(void *arg), void *arg,
+ size_t stack_size, void *stack)
+{
+ return ltp_clone_(flags, fn, arg, stack_size, stack, NULL, NULL, NULL);
+}
+
+int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg,
+ size_t stack_size, void *stack, ...)
+{
+ pid_t *ptid, *ctid;
+ void *tls;
+ va_list arg_clone;
+
+ va_start(arg_clone, stack);
+ ptid = va_arg(arg_clone, pid_t *);
+ tls = va_arg(arg_clone, void *);
+ ctid = va_arg(arg_clone, pid_t *);
+ va_end(arg_clone);
+
+#ifdef CLONE_SUPPORTS_7_ARGS
+ return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/*
+ * ltp_alloc_stack: allocate stack of size 'size', that is sufficiently
+ * aligned for all arches. User is responsible for freeing allocated
+ * memory.
+ * Returns pointer to new stack. On error, returns NULL with errno set.
+ */
+void *ltp_alloc_stack(size_t size)
+{
+ void *ret = NULL;
+ int err;
+
+ err = posix_memalign(&ret, 64, size);
+ if (err)
+ errno = err;
+
+ return ret;
+}
+
+/*
+ * ltp_clone_alloc: also does the memory allocation for clone with a
+ * caller-specified size.
+ */
+int
+ltp_clone_alloc(unsigned long clone_flags, int (*fn) (void *arg), void *arg,
+ size_t stack_size)
+{
+ void *stack;
+ int ret;
+ int saved_errno;
+
+ stack = ltp_alloc_stack(stack_size);
+ if (stack == NULL)
+ return -1;
+
+ ret = ltp_clone(clone_flags, fn, arg, stack_size, stack);
+
+ if (ret == -1) {
+ saved_errno = errno;
+ free(stack);
+ errno = saved_errno;
+ }
+
+ return ret;
+}
+
+/*
+ * ltp_clone_quick: calls ltp_clone_alloc with predetermined stack size.
+ * Experience thus far suggests that one page is often insufficient,
+ * while 6*getpagesize() seems adequate.
+ */
+int ltp_clone_quick(unsigned long clone_flags, int (*fn) (void *arg), void *arg)
+{
+ size_t stack_size = getpagesize() * 6;
+
+ return ltp_clone_alloc(clone_flags, fn, arg, stack_size);
+}
diff --git a/src/kernel/tests/lib/errnos.h b/src/kernel/tests/lib/errnos.h
new file mode 100644
index 0000000..df8fea8
--- /dev/null
+++ b/src/kernel/tests/lib/errnos.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2009-2013 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ */
+
+const char *tst_strerrno(int err)
+{
+ static const struct pair errno_pairs[] = {
+ STRPAIR(0, "SUCCESS")
+ /* asm-generic/errno-base.h */
+ PAIR(EPERM)
+ PAIR(ENOENT)
+ PAIR(ESRCH)
+ PAIR(EINTR)
+ PAIR(EIO)
+ PAIR(ENXIO)
+ PAIR(E2BIG)
+ PAIR(ENOEXEC)
+ PAIR(EBADF)
+ PAIR(ECHILD)
+ STRPAIR(EAGAIN, "EAGAIN/EWOULDBLOCK")
+ PAIR(ENOMEM)
+ PAIR(EACCES)
+ PAIR(EFAULT)
+ PAIR(ENOTBLK)
+ PAIR(EBUSY)
+ PAIR(EEXIST)
+ PAIR(EXDEV)
+ PAIR(ENODEV)
+ PAIR(ENOTDIR)
+ PAIR(EISDIR)
+ PAIR(EINVAL)
+ PAIR(ENFILE)
+ PAIR(EMFILE)
+ PAIR(ENOTTY)
+ PAIR(ETXTBSY)
+ PAIR(EFBIG)
+ PAIR(ENOSPC)
+ PAIR(ESPIPE)
+ PAIR(EROFS)
+ PAIR(EMLINK)
+ PAIR(EPIPE)
+ PAIR(EDOM)
+ PAIR(ERANGE)
+ /* asm-generic/errno.h */
+ PAIR(EDEADLK)
+ PAIR(ENAMETOOLONG)
+ PAIR(ENOLCK)
+ PAIR(ENOSYS)
+ PAIR(ENOTEMPTY)
+ PAIR(ELOOP)
+ /* EWOULDBLOCK == EAGAIN skipped */
+ PAIR(ENOMSG)
+ PAIR(EIDRM)
+ PAIR(ECHRNG)
+ PAIR(EL2NSYNC)
+ PAIR(EL3HLT)
+ PAIR(EL3RST)
+ PAIR(ELNRNG)
+ PAIR(EUNATCH)
+ PAIR(ENOCSI)
+ PAIR(EL2HLT)
+ PAIR(EBADE)
+ PAIR(EBADR)
+ PAIR(EXFULL)
+ PAIR(ENOANO)
+ PAIR(EBADRQC)
+ PAIR(EBADSLT)
+ /* EDEADLOCK == EDEADLK skipped */
+ PAIR(EBFONT)
+ PAIR(ENOSTR)
+ PAIR(ENODATA)
+ PAIR(ETIME)
+ PAIR(ENOSR)
+ PAIR(ENONET)
+ PAIR(ENOPKG)
+ PAIR(EREMOTE)
+ PAIR(ENOLINK)
+ PAIR(EADV)
+ PAIR(ESRMNT)
+ PAIR(ECOMM)
+ PAIR(EPROTO)
+ PAIR(EMULTIHOP)
+ PAIR(EDOTDOT)
+ PAIR(EBADMSG)
+ PAIR(EOVERFLOW)
+ PAIR(ENOTUNIQ)
+ PAIR(EBADFD)
+ PAIR(EREMCHG)
+ PAIR(ELIBACC)
+ PAIR(ELIBBAD)
+ PAIR(ELIBSCN)
+ PAIR(ELIBMAX)
+ PAIR(ELIBEXEC)
+ PAIR(EILSEQ)
+ PAIR(ERESTART)
+ PAIR(ESTRPIPE)
+ PAIR(EUSERS)
+ PAIR(ENOTSOCK)
+ PAIR(EDESTADDRREQ)
+ PAIR(EMSGSIZE)
+ PAIR(EPROTOTYPE)
+ PAIR(ENOPROTOOPT)
+ PAIR(EPROTONOSUPPORT)
+ PAIR(ESOCKTNOSUPPORT)
+ PAIR(EOPNOTSUPP)
+ PAIR(EPFNOSUPPORT)
+ PAIR(EAFNOSUPPORT)
+ PAIR(EADDRINUSE)
+ PAIR(EADDRNOTAVAIL)
+ PAIR(ENETDOWN)
+ PAIR(ENETUNREACH)
+ PAIR(ENETRESET)
+ PAIR(ECONNABORTED)
+ PAIR(ECONNRESET)
+ PAIR(ENOBUFS)
+ PAIR(EISCONN)
+ PAIR(ENOTCONN)
+ PAIR(ESHUTDOWN)
+ PAIR(ETOOMANYREFS)
+ PAIR(ETIMEDOUT)
+ PAIR(ECONNREFUSED)
+ PAIR(EHOSTDOWN)
+ PAIR(EHOSTUNREACH)
+ PAIR(EALREADY)
+ PAIR(EINPROGRESS)
+ PAIR(ESTALE)
+ PAIR(EUCLEAN)
+ PAIR(ENOTNAM)
+ PAIR(ENAVAIL)
+ PAIR(EISNAM)
+ PAIR(EREMOTEIO)
+ PAIR(EDQUOT)
+ PAIR(ENOMEDIUM)
+ PAIR(EMEDIUMTYPE)
+ PAIR(ECANCELED)
+#ifdef ENOKEY
+ PAIR(ENOKEY)
+#endif
+#ifdef EKEYEXPIRED
+ PAIR(EKEYEXPIRED)
+#endif
+#ifdef EKEYREVOKED
+ PAIR(EKEYREVOKED)
+#endif
+#ifdef EKEYREJECTED
+ PAIR(EKEYREJECTED)
+#endif
+#ifdef EOWNERDEAD
+ PAIR(EOWNERDEAD)
+#endif
+#ifdef ENOTRECOVERABLE
+ PAIR(ENOTRECOVERABLE)
+#endif
+#ifdef ERFKILL
+ PAIR(ERFKILL)
+#endif
+#ifdef EHWPOISON
+ PAIR(EHWPOISON)
+#endif
+ };
+
+ PAIR_LOOKUP(errno_pairs, err);
+}
diff --git a/src/kernel/tests/lib/get_path.c b/src/kernel/tests/lib/get_path.c
new file mode 100644
index 0000000..aafbc2c
--- /dev/null
+++ b/src/kernel/tests/lib/get_path.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+ /*
+ * Looks for binary prog_name in $PATH.
+ *
+ * If such file exists and if you are able at least to read it, zero is
+ * returned and absolute path to the file is filled into buf. In case buf is
+ * too short to hold the absolute path + prog_name for the file we are looking
+ * for -1 is returned as well as when there is no such file in all paths in
+ * $PATH.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "test.h"
+
+static int file_exist(const char *path)
+{
+ struct stat st;
+
+ if (!access(path, R_OK) && !stat(path, &st) && S_ISREG(st.st_mode))
+ return 1;
+
+ return 0;
+}
+
+int tst_get_path(const char *prog_name, char *buf, size_t buf_len)
+{
+ const char *path = (const char *)getenv("PATH");
+ const char *start = path;
+ const char *end;
+ size_t size, ret;
+
+ if (path == NULL)
+ return -1;
+
+ do {
+ end = strchr(start, ':');
+
+ if (end != NULL)
+ snprintf(buf, MIN(buf_len, (size_t) (end - start + 1)),
+ "%s", start);
+ else
+ snprintf(buf, buf_len, "%s", start);
+
+ size = strlen(buf);
+
+ /*
+ * "::" inside $PATH, $PATH ending with ':' or $PATH starting
+ * with ':' should be expanded into current working directory.
+ */
+ if (size == 0) {
+ snprintf(buf, buf_len, ".");
+ size = strlen(buf);
+ }
+
+ /*
+ * If there is no '/' ad the end of path from $PATH add it.
+ */
+ if (buf[size - 1] != '/')
+ ret =
+ snprintf(buf + size, buf_len - size, "/%s",
+ prog_name);
+ else
+ ret =
+ snprintf(buf + size, buf_len - size, "%s",
+ prog_name);
+
+ if (buf_len - size > ret && file_exist(buf))
+ return 0;
+
+ start = end + 1;
+
+ } while (end != NULL);
+
+ return -1;
+}
diff --git a/src/kernel/tests/lib/parse_opts.c b/src/kernel/tests/lib/parse_opts.c
new file mode 100644
index 0000000..a9d5058
--- /dev/null
+++ b/src/kernel/tests/lib/parse_opts.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * AUTHOR : William Roske/Richard Logan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+#include "config.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdint.h>
+
+#include "test.h"
+#include "ltp_priv.h"
+#include "usctest.h"
+#include "tst_clocks.h"
+
+#ifndef UNIT_TEST
+#define UNIT_TEST 0
+#endif
+
+/* Define flags and args for standard options */
+static int STD_INFINITE = 0; /* flag indciating to loop forever */
+int STD_LOOP_COUNT = 1; /* number of iterations */
+
+static float STD_LOOP_DURATION = 0.0; /* duration value in fractional seconds */
+
+static char **STD_opt_arr = NULL; /* array of option strings */
+static int STD_argind = 1; /* argv index to next argv element */
+ /* (first argument) */
+ /* To getopt users, it is like optind */
+
+/*
+ * The following variables are to support system testing additions.
+ */
+static int STD_TP_barrier = 0; /* flag to do barrier in TEST_PAUSE */
+ /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */
+static int STD_LP_barrier = 0; /* flag to do barrier in TEST_LOOPING */
+ /* 2 - wait_barrier(), 3 - set_barrier(), * - barrier() */
+static int STD_TP_shmem_sz = 0; /* shmalloc this many words per pe in TEST_PAUSE */
+static int STD_LD_shmem = 0; /* flag to do shmem_puts and shmem_gets during delay */
+static int STD_LP_shmem = 0; /* flag to do shmem_puts and gets during TEST_LOOPING */
+static int STD_LD_recfun = 0; /* do recressive function calls in loop delay */
+static int STD_LP_recfun = 0; /* do recressive function calls in TEST_LOOPING */
+static int STD_TP_sbrk = 0; /* do sbrk in TEST_PAUSE */
+static int STD_LP_sbrk = 0; /* do sbrk in TEST_LOOPING */
+static char *STD_start_break = 0; /* original sbrk size */
+static int Debug = 0;
+
+static struct std_option_t {
+ char *optstr;
+ char *help;
+ char *flag;
+ char **arg;
+} std_options[] = {
+ {"h", " -h Show this help screen\n", NULL, NULL},
+ {"i:", " -i n Execute test n times\n", NULL, NULL},
+ {"I:", " -I x Execute test for x seconds\n", NULL, NULL},
+#ifdef UCLINUX
+ {"C:",
+ " -C ARG Run the child process with arguments ARG (for internal use)\n",
+ NULL, NULL},
+#endif
+ {NULL, NULL, NULL, NULL}
+};
+
+/*
+ * Structure for usc_recressive_func argument
+ */
+struct usc_bigstack_t {
+ char space[4096];
+};
+
+static struct usc_bigstack_t *STD_bigstack = NULL;
+
+/* define the string length for Mesg and Mesg2 strings */
+#define STRLEN 2048
+
+static char Mesg2[STRLEN]; /* holds possible return string */
+static void usc_recressive_func();
+
+/*
+ * Define bits for options that might have env variable default
+ */
+#define OPT_iteration 01
+#define OPT_duration 04
+#define OPT_delay 010
+
+#ifdef UCLINUX
+/* Allocated and used in self_exec.c: */
+extern char *child_args; /* Arguments to child when -C is used */
+#endif
+
+static void print_help(void (*user_help)(void))
+{
+ int i;
+
+ for (i = 0; std_options[i].optstr; ++i) {
+ if (std_options[i].help)
+ printf("%s", std_options[i].help);
+ }
+
+ if (user_help)
+ user_help();
+}
+
+/**********************************************************************
+ * parse_opts:
+ **********************************************************************/
+const char *parse_opts(int ac, char **av, const option_t * user_optarr,
+ void (*uhf)(void))
+{
+ int found; /* flag to indicate that an option specified was */
+ /* found in the user's list */
+ int k; /* scratch integer for returns and short time usage */
+ float ftmp; /* tmp float for parsing env variables */
+ char *ptr; /* used in getting env variables */
+ int options = 0; /* no options specified */
+ int optstrlen, i;
+ char *optionstr;
+ int opt;
+
+ /*
+ * If not the first time this function is called, release the old STD_opt_arr
+ * vector.
+ */
+ if (STD_opt_arr != NULL) {
+ free(STD_opt_arr);
+ STD_opt_arr = NULL;
+ }
+ /* Calculate how much space we need for the option string */
+ optstrlen = 0;
+ for (i = 0; std_options[i].optstr; ++i)
+ optstrlen += strlen(std_options[i].optstr);
+ if (user_optarr)
+ for (i = 0; user_optarr[i].option; ++i) {
+ if (strlen(user_optarr[i].option) > 2)
+ return
+ "parse_opts: ERROR - Only short options are allowed";
+ optstrlen += strlen(user_optarr[i].option);
+ }
+ optstrlen += 1;
+
+ /* Create the option string for getopt */
+ optionstr = malloc(optstrlen);
+ if (!optionstr)
+ return
+ "parse_opts: ERROR - Could not allocate memory for optionstr";
+
+ optionstr[0] = '\0';
+
+ for (i = 0; std_options[i].optstr; ++i)
+ strcat(optionstr, std_options[i].optstr);
+ if (user_optarr)
+ for (i = 0; user_optarr[i].option; ++i)
+ /* only add the option if it wasn't there already */
+ if (strchr(optionstr, user_optarr[i].option[0]) == NULL)
+ strcat(optionstr, user_optarr[i].option);
+
+ /*
+ * Loop through av parsing options.
+ */
+ while ((opt = getopt(ac, av, optionstr)) > 0) {
+
+ STD_argind = optind;
+
+ switch (opt) {
+ case '?': /* Unknown option */
+ return "Unknown option";
+ break;
+ case ':': /* Missing Arg */
+ return "Missing argument";
+ break;
+ case 'i': /* Iterations */
+ options |= OPT_iteration;
+ STD_LOOP_COUNT = atoi(optarg);
+ if (STD_LOOP_COUNT == 0)
+ STD_INFINITE = 1;
+ break;
+ case 'I': /* Time duration */
+ options |= OPT_duration;
+ STD_LOOP_DURATION = atof(optarg);
+ if (STD_LOOP_DURATION == 0.0)
+ STD_INFINITE = 1;
+ break;
+ case 'h': /* Help */
+ print_help(uhf);
+ exit(0);
+ break;
+#ifdef UCLINUX
+ case 'C': /* Run child */
+ child_args = optarg;
+ break;
+#endif
+ default:
+
+ /* Check all the user specified options */
+ found = 0;
+ for (i = 0; user_optarr[i].option; ++i) {
+
+ if (opt == user_optarr[i].option[0]) {
+ /* Yup, This is a user option, set the flag and look for argument */
+ if (user_optarr[i].flag) {
+ *user_optarr[i].flag = 1;
+ }
+ found++;
+
+ /* save the argument at the user's location */
+ if (user_optarr[i].
+ option[strlen(user_optarr[i].option)
+ - 1] == ':') {
+ *user_optarr[i].arg = optarg;
+ }
+ break; /* option found - break out of the for loop */
+ }
+ }
+ /* This condition "should never happen". SO CHECK FOR IT!!!! */
+ if (!found) {
+ sprintf(Mesg2,
+ "parse_opts: ERROR - option:\"%c\" NOT FOUND... INTERNAL "
+ "ERROR", opt);
+ return (Mesg2);
+ }
+ }
+
+ }
+ free(optionstr);
+
+ STD_argind = optind;
+
+ /*
+ * Turn on debug
+ */
+ if (getenv("USC_DEBUG") != NULL) {
+ Debug = 1;
+ printf("env USC_DEBUG is defined, turning on debug\n");
+ }
+ if (getenv("USC_VERBOSE") != NULL) {
+ Debug = 1;
+ printf("env USC_VERBOSE is defined, turning on debug\n");
+ }
+
+ /*
+ * If the USC_ITERATION_ENV environmental variable is set to
+ * a number, use that number as iteration count (same as -c option).
+ * The -c option with arg will be used even if this env var is set.
+ */
+ if (!(options & OPT_iteration)
+ && (ptr = getenv(USC_ITERATION_ENV)) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1) {
+ if (k == 0) { /* if arg is 0, set infinite loop flag */
+ STD_INFINITE = 1;
+ if (Debug)
+ printf
+ ("Using env %s, set STD_INFINITE to 1\n",
+ USC_ITERATION_ENV);
+ } else { /* else, set the loop count to the arguement */
+ STD_LOOP_COUNT = k;
+ if (Debug)
+ printf
+ ("Using env %s, set STD_LOOP_COUNT to %d\n",
+ USC_ITERATION_ENV, k);
+ }
+ }
+ }
+
+ /*
+ * If the USC_LOOP_WALLTIME environmental variable is set,
+ * use that number as duration (same as -I option).
+ * The -I option with arg will be used even if this env var is set.
+ */
+
+ if (!(options & OPT_duration) &&
+ (ptr = getenv(USC_LOOP_WALLTIME)) != NULL) {
+ if (sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0) {
+ STD_LOOP_DURATION = ftmp;
+ if (Debug)
+ printf
+ ("Using env %s, set STD_LOOP_DURATION to %f\n",
+ USC_LOOP_WALLTIME, ftmp);
+ if (STD_LOOP_DURATION == 0.0) { /* if arg is 0, set infinite loop flag */
+ STD_INFINITE = 1;
+ if (Debug)
+ printf
+ ("Using env %s, set STD_INFINITE to 1\n",
+ USC_LOOP_WALLTIME);
+ }
+ }
+ }
+ if (!(options & OPT_duration) && (ptr = getenv("USC_DURATION")) != NULL) {
+ if (sscanf(ptr, "%f", &ftmp) == 1 && ftmp >= 0.0) {
+ STD_LOOP_DURATION = ftmp;
+ if (Debug)
+ printf
+ ("Using env USC_DURATION, set STD_LOOP_DURATION to %f\n",
+ ftmp);
+ if (STD_LOOP_DURATION == 0.0) { /* if arg is 0, set infinite loop flag */
+ STD_INFINITE = 1;
+ if (Debug)
+ printf
+ ("Using env USC_DURATION, set STD_INFINITE to 1\n");
+ }
+ }
+ }
+
+ /*
+ * The following are special system testing envs to turn on special
+ * hooks in the code.
+ */
+ if ((ptr = getenv("USC_TP_BARRIER")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0)
+ STD_TP_barrier = k;
+ else
+ STD_TP_barrier = 1;
+ if (Debug)
+ printf
+ ("using env USC_TP_BARRIER, Set STD_TP_barrier to %d\n",
+ STD_TP_barrier);
+ }
+
+ if ((ptr = getenv("USC_LP_BARRIER")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0)
+ STD_LP_barrier = k;
+ else
+ STD_LP_barrier = 1;
+ if (Debug)
+ printf
+ ("using env USC_LP_BARRIER, Set STD_LP_barrier to %d\n",
+ STD_LP_barrier);
+ }
+
+ if ((ptr = getenv("USC_TP_SHMEM")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_TP_shmem_sz = k;
+ if (Debug)
+ printf
+ ("Using env USC_TP_SHMEM, Set STD_TP_shmem_sz to %d\n",
+ STD_TP_shmem_sz);
+ }
+ }
+
+ if ((ptr = getenv("USC_LP_SHMEM")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_LP_shmem = k;
+ if (Debug)
+ printf
+ ("Using env USC_LP_SHMEM, Set STD_LP_shmem to %d\n",
+ STD_LP_shmem);
+ }
+ }
+
+ if ((ptr = getenv("USC_LD_SHMEM")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_LD_shmem = k;
+ if (Debug)
+ printf
+ ("Using env USC_LD_SHMEM, Set STD_LD_shmem to %d\n",
+ STD_LD_shmem);
+ }
+ }
+
+ if ((ptr = getenv("USC_TP_SBRK")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_TP_sbrk = k;
+ if (Debug)
+ printf
+ ("Using env USC_TP_SBRK, Set STD_TP_sbrk to %d\n",
+ STD_TP_sbrk);
+ }
+ }
+#if !defined(UCLINUX)
+ if ((ptr = getenv("USC_LP_SBRK")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_LP_sbrk = k;
+ if (Debug)
+ printf
+ ("Using env USC_LP_SBRK, Set STD_LP_sbrk to %d\n",
+ STD_LP_sbrk);
+ }
+ }
+#endif /* if !defined(UCLINUX) */
+
+ if ((ptr = getenv("USC_LP_RECFUN")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_LP_recfun = k;
+ if (STD_bigstack != NULL)
+ STD_bigstack =
+ malloc(sizeof(struct usc_bigstack_t));
+ if (Debug)
+ printf
+ ("Using env USC_LP_RECFUN, Set STD_LP_recfun to %d\n",
+ STD_LP_recfun);
+ }
+ }
+
+ if ((ptr = getenv("USC_LD_RECFUN")) != NULL) {
+ if (sscanf(ptr, "%i", &k) == 1 && k >= 0) {
+ STD_LD_recfun = k;
+ if (STD_bigstack != NULL)
+ STD_bigstack =
+ malloc(sizeof(struct usc_bigstack_t));
+ if (Debug)
+ printf
+ ("Using env USC_LD_RECFUN, Set STD_LD_recfun to %d\n",
+ STD_LD_recfun);
+ }
+ }
+#if UNIT_TEST
+ printf("The following variables after option and env parsing:\n");
+ printf("STD_LOOP_DURATION = %f\n", STD_LOOP_DURATION);
+ printf("STD_LOOP_COUNT = %d\n", STD_LOOP_COUNT);
+ printf("STD_INFINITE = %d\n", STD_INFINITE);
+#endif
+
+ return NULL;
+}
+
+/***********************************************************************
+ * This function will do desired end of global setup test
+ * hooks.
+ ***********************************************************************/
+int usc_global_setup_hook(void)
+{
+#ifndef UCLINUX
+ if (STD_TP_sbrk || STD_LP_sbrk)
+ STD_start_break = sbrk(0); /* get original sbreak size */
+
+ if (STD_TP_sbrk) {
+ sbrk(STD_TP_sbrk);
+ if (Debug)
+ printf("after sbrk(%d)\n", STD_TP_sbrk);
+ }
+#endif
+ return 0;
+}
+
+#define USECS_PER_SEC 1000000 /* microseconds per second */
+
+static uint64_t get_current_time(void)
+{
+ struct timespec ts;
+
+ tst_clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ return (((uint64_t) ts.tv_sec) * USECS_PER_SEC) + ts.tv_nsec / 1000;
+}
+
+/***********************************************************************
+ *
+ * This function will determine if test should continue iterating
+ * If the STD_INFINITE flag is set, return 1.
+ * If the STD_LOOP_COUNT variable is set, compare it against
+ * the counter.
+ * If the STD_LOOP_DURATION variable is set, compare current time against
+ * calculated stop_time.
+ * This function will return 1 until all desired looping methods
+ * have been met.
+ *
+ * counter integer is supplied by the user program.
+ ***********************************************************************/
+int usc_test_looping(int counter)
+{
+ static int first_time = 1;
+ static uint64_t stop_time = 0;
+ int keepgoing = 0;
+
+ /*
+ * If this is the first iteration and we are looping for
+ * duration of STD_LOOP_DURATION seconds (fractional) or
+ * doing loop delays, get the clocks per second.
+ */
+ if (first_time) {
+ first_time = 0;
+
+ /*
+ * If looping for duration, calculate stop time in
+ * clocks.
+ */
+ if (STD_LOOP_DURATION) {
+ stop_time =
+ (uint64_t) (USECS_PER_SEC * STD_LOOP_DURATION)
+ + get_current_time();
+ }
+ }
+
+ if (STD_INFINITE)
+ keepgoing++;
+
+ if (STD_LOOP_COUNT && counter < STD_LOOP_COUNT)
+ keepgoing++;
+
+ if (STD_LOOP_DURATION != 0.0 && get_current_time() < stop_time)
+ keepgoing++;
+
+ if (keepgoing == 0)
+ return 0;
+
+ /*
+ * The following code allows special system testing hooks.
+ */
+
+ if (STD_LP_recfun) {
+ if (Debug)
+ printf
+ ("calling usc_recressive_func(0, %d, *STD_bigstack)\n",
+ STD_LP_recfun);
+ usc_recressive_func(0, STD_LP_recfun, *STD_bigstack);
+ }
+#if !defined(UCLINUX)
+ if (STD_LP_sbrk) {
+ if (Debug)
+ printf("about to do sbrk(%d)\n", STD_LP_sbrk);
+ sbrk(STD_LP_sbrk);
+ }
+#endif
+
+ if (keepgoing)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * This function recressively calls itself max times.
+ */
+static void usc_recressive_func(int cnt, int max, struct usc_bigstack_t bstack)
+{
+ if (cnt < max)
+ usc_recressive_func(cnt + 1, max, bstack);
+
+}
+
+#if UNIT_TEST
+
+/******************************************************************************
+ * UNIT TEST CODE
+ * UNIT TEST CODE
+ *
+ * this following code is provide so that unit testing can
+ * be done fairly easily.
+ ******************************************************************************/
+
+int Help = 0;
+int Help2 = 0;
+char *ptr;
+
+long TEST_RETURN;
+int TEST_ERRNO;
+
+/* for test specific parse_opts options */
+option_t Options[] = {
+ {"help", &Help2, NULL}, /* -help option */
+ {"h", &Help, NULL}, /* -h option */
+
+#if INVALID_TEST_CASES
+ {"missingflag", NULL, &ptr}, /* error */
+ {"missingarg:", &Help, NULL}, /* error */
+#endif /* INVALID_TEST_CASES */
+
+ {NULL, NULL, NULL}
+};
+
+int main(int argc, char **argv)
+{
+ int lc;
+ char *msg;
+ struct timeval t;
+ int cnt;
+
+ if ((msg = parse_opts(argc, argv, Options, NULL)) != NULL) {
+ printf("ERROR: %s\n", msg);
+ exit(1);
+ }
+
+ TEST_PAUSE;
+
+ for (lc = 0; TEST_LOOPING(lc); lc++) {
+
+ TEST(gettimeofday(&t, NULL));
+ printf("iter=%d: sec:%d, usec:%6.6d %s", lc + 1, t.tv_sec,
+ t.tv_usec, ctime(&t.tv_sec));
+ }
+
+ TEST_CLEANUP;
+
+ exit(0);
+}
+
+#endif /* UNIT_TEST */
diff --git a/src/kernel/tests/lib/random_range.c b/src/kernel/tests/lib/random_range.c
new file mode 100644
index 0000000..510a4a1
--- /dev/null
+++ b/src/kernel/tests/lib/random_range.c
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include "random_range.h"
+
+/*
+ * Internal format of the range array set up by parse_range()
+ */
+
+struct range {
+ int min;
+ int max;
+ int mult;
+};
+
+/*
+ * parse_ranges() is a function to parse a comma-separated list of range
+ * tokens each having the following form:
+ *
+ * num
+ * or
+ * min:max[:mult]
+ *
+ * any of the values may be blank (ie. min::mult, :max, etc.) and default
+ * values for missing arguments may be supplied by the caller.
+ *
+ * The special first form is short hand for 'num:num'.
+ *
+ * After parsing the string, the ranges are put into an array of integers,
+ * which is malloc'd by the routine. The min, max, and mult entries of each
+ * range can be extracted from the array using the range_min(), range_max(),
+ * and range_mult() functions.
+ *
+ * It is the responsibility of the caller to free the space allocated by
+ * parse_ranges() - a single call to free() will free the space.
+ *
+ * str The string to parse - assumed to be a comma-separated
+ * list of tokens having the above format.
+ * defmin default value to plug in for min, if it is missing
+ * defmax default value to plug in for max, if it is missing
+ * defmult default value to plug in for mult, if missing
+ * parse_func A user-supplied function pointer, which parse_ranges()
+ * can call to parse the min, max, and mult strings. This
+ * allows for customized number formats. The function
+ * MUST have the following prototype:
+ * parse_func(char *str, int *val)
+ * The function should return -1 if str cannot be parsed
+ * into an integer, or >= 0 if it was successfully
+ * parsed. The resulting integer will be stored in
+ * *val. If parse_func is NULL, parse_ranges will parse
+ * the tokens in a manner consistent with the the sscanf
+ * %i format.
+ * range_ptr A user-supplied char **, which will be set to point
+ * at malloc'd space which holds the parsed range
+ * values. If range_ptr is NULL, parse_ranges() just
+ * parses the string. The data returned in range_ptr
+ * should not be processed directly - use the functions
+ * range_min(), range_max(), and range_mult() to access
+ * data for a given range.
+ * errptr user-supplied char ** which can be set to point to a
+ * static error string. If errptr is NULL, it is ignored.
+ *
+ * parse_range() returns -1 on error, or the number of ranges parsed.
+ */
+
+static int str_to_int();
+static long long divider(long long, long long, long long, long long);
+
+int parse_ranges(char *str, int defmin, int defmax, int defmult,
+ int (*parse_func)(), char **rangeptr, char **errptr)
+{
+ int ncommas;
+ char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr;
+ struct range *rp, *ranges;
+ static char errmsg[256];
+
+ if (errptr != NULL) {
+ *errptr = errmsg;
+ }
+
+ for (ncommas = 0, cp = str; *cp != '\0'; cp++) {
+ if (*cp == ',') {
+ ncommas++;
+ }
+ }
+
+ if (parse_func == NULL) {
+ parse_func = str_to_int;
+ }
+
+ tmpstr = strdup(str);
+ ranges = malloc((ncommas + 1) * sizeof(struct range));
+ rp = ranges;
+
+ tok = strtok(tmpstr, ",");
+ while (tok != NULL) {
+ n1str = tok;
+ n2str = NULL;
+ multstr = NULL;
+
+ rp->min = defmin;
+ rp->max = defmax;
+ rp->mult = defmult;
+
+ if ((cp = strchr(n1str, ':')) != NULL) {
+ *cp = '\0';
+ n2str = cp + 1;
+
+ if ((cp = strchr(n2str, ':')) != NULL) {
+ *cp = '\0';
+ multstr = cp + 1;
+ }
+ }
+
+ /*
+ * Parse the 'min' field - if it is zero length (:n2[:mult]
+ * format), retain the default value, otherwise, pass the
+ * string to the parse function.
+ */
+
+ if ((int)strlen(n1str) > 0) {
+ if ((*parse_func) (n1str, &rp->min) < 0) {
+ sprintf(errmsg,
+ "error parsing string %s into an integer",
+ n1str);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ /*
+ * Process the 'max' field - if one was not present (n1 format)
+ * set max equal to min. If the field was present, but
+ * zero length (n1: format), retain the default. Otherwise
+ * pass the string to the parse function.
+ */
+
+ if (n2str == NULL) {
+ rp->max = rp->min;
+ } else if ((int)strlen(n2str) > 0) {
+ if ((*parse_func) (n2str, &rp->max) < 0) {
+ sprintf(errmsg,
+ "error parsing string %s into an integer",
+ n2str);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ /*
+ * Process the 'mult' field - if one was not present
+ * (n1:n2 format), or the field was zero length (n1:n2: format)
+ * then set the mult field to defmult - otherwise pass then
+ * mult field to the parse function.
+ */
+
+ if (multstr != NULL && (int)strlen(multstr) > 0) {
+ if ((*parse_func) (multstr, &rp->mult) < 0) {
+ sprintf(errmsg,
+ "error parsing string %s into an integer",
+ multstr);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ rp++;
+ tok = strtok(NULL, ",");
+ }
+
+ free(tmpstr);
+
+ if (rangeptr != NULL) {
+ *rangeptr = (char *)ranges;
+ } else {
+ free(ranges); /* just running in parse mode */
+ }
+
+ return (rp - ranges);
+}
+
+/*
+ * The default integer-parsing function
+ */
+
+static int str_to_int(char *str, int *ip)
+{
+ char c;
+
+ if (sscanf(str, "%i%c", ip, &c) != 1) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Three simple functions to return the min, max, and mult values for a given
+ * range. It is assumed that rbuf is a range buffer set up by parse_ranges(),
+ * and that r is a valid range within that buffer.
+ */
+
+int range_min(char *rbuf, int r)
+{
+ return ((struct range *)rbuf)[r].min;
+}
+
+int range_max(char *rbuf, int r)
+{
+ return ((struct range *)rbuf)[r].max;
+}
+
+int range_mult(char *rbuf, int r)
+{
+ return ((struct range *)rbuf)[r].mult;
+}
+
+/*****************************************************************************
+ * random_range(int start, int end, int mult, char **errp)
+ *
+ * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple
+ * of 'mult'. Start and end may be any valid integer, but mult must be an
+ * integer > 0. errp is a char ** which will be set to point to a static
+ * error message buffer if it is not NULL, and an error occurs.
+ *
+ * The errp is the only way to check if the routine fails - currently the only
+ * failure conditions are:
+ *
+ * mult < 1
+ * no numbers in the start-end range that are a multiple of 'mult'
+ *
+ * If random_range_fails, and errp is a valid pointer, it will point to an
+ * internal error buffer. If errp is a vaild pointer, and random_range
+ * is successful, errp will be set to NULL.
+ *
+ * Note - if mult is 1 (the most common case), there are error conditions
+ * possible, and errp need not be used.
+ *
+ * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when
+ * setting the seed.
+ *****************************************************************************/
+
+long random_range(int min, int max, int mult, char **errp)
+{
+ int r, nmults, orig_min, orig_max, orig_mult, tmp;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf,
+ "no numbers in the range %d:%d that are a multiple of %d",
+ orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+#if CRAY
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if (max <= (long)2147483647) {
+ return (long)(min + (((long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ long randnum;
+ randnum = divider(min, max, 0, -1);
+ return (long)(min + ((randnum % nmults) * mult));
+ }
+
+#else
+ return (min + ((lrand48() % nmults) * mult));
+#endif
+
+}
+
+/*
+ * Just like random_range, but all values are longs.
+ */
+long random_rangel(long min, long max, long mult, char **errp)
+{
+ long r, nmults, orig_min, orig_max, orig_mult, tmp;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf,
+ "no numbers in the range %ld:%ld that are a multiple of %ld",
+ orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+#if CRAY || (_MIPS_SZLONG == 64)
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if (max <= (long)2147483647) {
+ return (long)(min + (((long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ long randnum;
+ randnum = divider(min, max, 0, -1);
+ return (long)(min + ((randnum % nmults) * mult));
+ }
+
+#else
+ return (min + ((lrand48() % nmults) * mult));
+#endif
+}
+
+/*
+ * Attempts to be just like random_range, but everything is long long (64 bit)
+ */
+long long random_rangell(long long min, long long max,
+ long long mult, char **errp)
+{
+ long long r, nmults, orig_min, orig_max, orig_mult, tmp;
+ long long randnum;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf,
+ "no numbers in the range %lld:%lld that are a multiple of %lld",
+ orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if (max <= (long)2147483647) {
+ return (long long)(min +
+ (((long long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ randnum = divider(min, max, 0, -1);
+ return (long long)(min + ((randnum % nmults) * mult));
+ }
+
+}
+
+/*
+ * This functional will recusively call itself to return a random
+ * number min and max. It was designed to work the 64bit numbers
+ * even when compiled as 32 bit process.
+ * algorithm: to use the official lrand48() routine - limited to 32 bits.
+ * find the difference between min and max (max-min).
+ * if the difference is 2g or less, use the random number gotton from lrand48().
+ * Determine the midway point between min and max.
+ * if the midway point is less than 2g from min or max,
+ * randomly add the random number gotton from lrand48() to
+ * either min or the midpoint.
+ * Otherwise, call outself with min and max being min and midway value or
+ * midway value and max. This will reduce the range in half.
+ */
+static long long
+divider(long long min, long long max, long long cnt, long long rand)
+{
+ long long med, half, diff;
+
+ /*
+ * prevent run away code. We are dividing by two each count.
+ * if we get to a count of more than 32, we should have gotten
+ * to 2gb.
+ */
+ if (cnt > 32)
+ return -1;
+
+ /*
+ * Only get a random number the first time.
+ */
+ if (cnt == 0 || rand < -1) {
+ rand = (long long)lrand48(); /* 32 bit random number */
+ }
+
+ diff = max - min;
+
+ if (diff <= 2147483647)
+ return min + rand;
+
+ half = diff / (long long)2; /* half the distance between min and max */
+ med = min + half; /* med way point between min and max */
+
+#if DEBUG
+ printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max,
+ cnt, rand);
+ printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med);
+#endif
+
+ if (half <= 2147483647) {
+ /*
+ * If half is smaller than 2gb, we can use the random number
+ * to pick the number within the min to med or med to max
+ * if the cnt bit of rand is zero or one, respectively.
+ */
+ if (rand & (1 << cnt))
+ return med + rand;
+ else
+ return min + rand;
+ } else {
+ /*
+ * recursively call ourself to reduce the value to the bottom half
+ * or top half (bit cnt is set).
+ */
+ if (rand & (1 << cnt)) {
+ return divider(med, max, cnt + 1, rand);
+ } else {
+ return divider(min, med, cnt + 1, rand);
+ }
+
+ }
+
+}
+
+/*****************************************************************************
+ * random_range_seed(s)
+ *
+ * Sets the random seed to s. Uses srand48(), assuming that lrand48() will
+ * be used in random_range().
+ *****************************************************************************/
+
+void random_range_seed(long s)
+{
+ extern void srand48();
+
+ srand48(s);
+}
+
+/****************************************************************************
+ * random_bit(mask)
+ *
+ * This function randomly returns a single bit from the bits
+ * set in mask. If mask is zero, zero is returned.
+ *
+ ****************************************************************************/
+long random_bit(long mask)
+{
+ int nbits = 0; /* number of set bits in mask */
+ long bit; /* used to count bits and num of set bits choosen */
+ int nshift; /* used to count bit shifts */
+
+ if (mask == 0)
+ return 0;
+
+ /*
+ * get the number of bits set in mask
+ */
+#ifndef CRAY
+
+ bit = 1L;
+ for (nshift = 0; (unsigned int)nshift < sizeof(long) * 8; nshift++) {
+ if (mask & bit)
+ nbits++;
+ bit = bit << 1;
+ }
+
+#else
+ nbits = _popcnt(mask);
+#endif /* if CRAY */
+
+ /*
+ * randomly choose a bit.
+ */
+ bit = random_range(1, nbits, 1, NULL);
+
+ /*
+ * shift bits until you determine which bit was randomly choosen.
+ * nshift will hold the number of shifts to make.
+ */
+
+ nshift = 0;
+ while (bit) {
+ /* check if the current one's bit is set */
+ if (mask & 1L) {
+ bit--;
+ }
+ mask = mask >> 1;
+ nshift++;
+ }
+
+ return 01L << (nshift - 1);
+
+}
+
+#if RANDOM_BIT_UNITTEST
+/*
+ * The following is a unit test main function for random_bit().
+ */
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int ind;
+ int cnt, iter;
+ long mask, ret;
+
+ printf("test for first and last bit set\n");
+ mask = 1L;
+ ret = random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+ mask = 1L << (sizeof(long) * 8 - 1);
+ ret = random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+ if (argc >= 3) {
+ iter = atoi(argv[1]);
+ for (ind = 2; ind < argc; ind++) {
+ printf("Calling random_bit %d times for mask %#o\n",
+ iter, mask);
+ sscanf(argv[ind], "%i", &mask);
+ for (cnt = 0; cnt < iter; cnt++) {
+ ret = random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask,
+ ret);
+ }
+ }
+ }
+ exit(0);
+}
+
+#endif /* end if RANDOM_BIT_UNITTEST */
+
+#if UNIT_TEST
+/*
+ * The following is a unit test main function for random_range*().
+ */
+
+#define PARTNUM 10 /* used to determine even distribution of random numbers */
+#define MEG 1024*1024*1024
+#define GIG 1073741824
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ int ind;
+ int cnt, iter = 10;
+ int imin = 0, imult = 1, itmin, itmax = 0;
+#if CRAY
+ int imax = 6 * GIG; /* higher than 32 bits */
+#else
+ int imax = 1048576;
+#endif
+
+ long lret, lmin = 0, lmult = 1, ltmin, ltmax = 0;
+#if CRAY || (_MIPS_SZLONG == 64)
+ long lmax = 6 * (long)GIG; /* higher than 32 bits */
+#else
+ long lmax = 1048576;
+#endif
+ long long llret, llmin = 0, llmult = 1, lltmin, lltmax = 0;
+ long long llmax = (long long)80 * (long long)GIG;
+
+ long part;
+ long long lpart;
+ long cntarr[PARTNUM];
+ long valbound[PARTNUM];
+ long long lvalbound[PARTNUM];
+
+ for (ind = 0; ind < PARTNUM; ind++)
+ cntarr[ind] = 0;
+
+ if (argc < 2) {
+ printf("Usage: %s func [iterations] \n", argv[0]);
+ printf
+ ("func can be random_range, random_rangel, random_rangell\n");
+ exit(1);
+ }
+
+ if (argc >= 3) {
+ if (sscanf(argv[2], "%i", &iter) != 1) {
+ printf("Usage: %s [func iterations] \n", argv[0]);
+ printf("argv[2] is not a number\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * random_rangel ()
+ */
+ if (strcmp(argv[1], "random_rangel") == 0) {
+ ltmin = lmax;
+ part = lmax / PARTNUM;
+ for (ind = 0; ind < PARTNUM; ind++) {
+ valbound[ind] = part * ind;
+ }
+
+ for (cnt = 0; cnt < iter; cnt++) {
+ lret = random_rangel(lmin, lmax, lmult, NULL);
+ if (iter < 100)
+ printf("%ld\n", lret);
+ if (lret < ltmin)
+ ltmin = lret;
+ if (lret > ltmax)
+ ltmax = lret;
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ if (valbound[ind] < lret
+ && lret <= valbound[ind + 1]) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if (lret > valbound[PARTNUM - 1]) {
+ cntarr[PARTNUM - 1]++;
+ }
+ }
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1,
+ valbound[ind], valbound[ind + 1], cntarr[ind],
+ (float)(cntarr[ind] / (float)iter));
+ }
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
+ valbound[PARTNUM - 1], lmax, cntarr[PARTNUM - 1],
+ (float)(cntarr[PARTNUM - 1] / (float)iter));
+ printf(" min=%ld, max=%ld\n", ltmin, ltmax);
+
+ } else if (strcmp(argv[1], "random_rangell") == 0) {
+ /*
+ * random_rangell() unit test
+ */
+ lltmin = llmax;
+ lpart = llmax / PARTNUM;
+ for (ind = 0; ind < PARTNUM; ind++) {
+ lvalbound[ind] = (long long)(lpart * ind);
+ }
+
+ for (cnt = 0; cnt < iter; cnt++) {
+ llret = random_rangell(llmin, llmax, llmult, NULL);
+ if (iter < 100)
+ printf("random_rangell returned %lld\n", llret);
+ if (llret < lltmin)
+ lltmin = llret;
+ if (llret > lltmax)
+ lltmax = llret;
+
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ if (lvalbound[ind] < llret
+ && llret <= lvalbound[ind + 1]) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if (llret > lvalbound[PARTNUM - 1]) {
+ cntarr[PARTNUM - 1]++;
+ }
+ }
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ printf("%2d %-13lld to %-13lld %5ld %4.4f\n",
+ ind + 1, lvalbound[ind], lvalbound[ind + 1],
+ cntarr[ind], (float)(cntarr[ind] / (float)iter));
+ }
+ printf("%2d %-13lld to %-13lld %5ld %4.4f\n", PARTNUM,
+ lvalbound[PARTNUM - 1], llmax, cntarr[PARTNUM - 1],
+ (float)(cntarr[PARTNUM - 1] / (float)iter));
+ printf(" min=%lld, max=%lld\n", lltmin, lltmax);
+
+ } else {
+ /*
+ * random_range() unit test
+ */
+ itmin = imax;
+ part = imax / PARTNUM;
+ for (ind = 0; ind < PARTNUM; ind++) {
+ valbound[ind] = part * ind;
+ }
+
+ for (cnt = 0; cnt < iter; cnt++) {
+ lret = random_range(imin, imax, imult, NULL);
+ if (iter < 100)
+ printf("%ld\n", lret);
+ if (lret < itmin)
+ itmin = lret;
+ if (lret > itmax)
+ itmax = lret;
+
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ if (valbound[ind] < lret
+ && lret <= valbound[ind + 1]) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if (lret > valbound[PARTNUM - 1]) {
+ cntarr[PARTNUM - 1]++;
+ }
+ }
+ for (ind = 0; ind < PARTNUM - 1; ind++) {
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind + 1,
+ valbound[ind], valbound[ind + 1], cntarr[ind],
+ (float)(cntarr[ind] / (float)iter));
+ }
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
+ valbound[PARTNUM - 1], (long)imax, cntarr[PARTNUM - 1],
+ (float)(cntarr[PARTNUM - 1] / (float)iter));
+ printf(" min=%d, max=%d\n", itmin, itmax);
+
+ }
+
+ exit(0);
+}
+
+#endif
diff --git a/src/kernel/tests/lib/safe_file_ops.c b/src/kernel/tests/lib/safe_file_ops.c
new file mode 100644
index 0000000..e06d399
--- /dev/null
+++ b/src/kernel/tests/lib/safe_file_ops.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "test.h"
+#include "safe_file_ops_fn.h"
+
+/*
+ * Count number of expected assigned conversions. Any conversion starts with '%'.
+ * The '%%' matches % and no assignment is done. The %*x matches as x would do but
+ * the assignment is suppressed.
+ *
+ * NOTE: This is not 100% correct for complex scanf strings, but will do for
+ * all of our intended usage.
+ */
+static int count_scanf_conversions(const char *fmt)
+{
+ unsigned int cnt = 0;
+ int flag = 0;
+
+ while (*fmt) {
+ switch (*fmt) {
+ case '%':
+ if (flag) {
+ cnt--;
+ flag = 0;
+ } else {
+ flag = 1;
+ cnt++;
+ }
+ break;
+ case '*':
+ if (flag) {
+ cnt--;
+ flag = 0;
+ }
+ break;
+ default:
+ flag = 0;
+ }
+
+ fmt++;
+ }
+
+ return cnt;
+}
+
+int file_scanf(const char *file, const int lineno,
+ const char *path, const char *fmt, ...)
+{
+ va_list va;
+ FILE *f;
+ int exp_convs, ret;
+
+ f = fopen(path, "r");
+
+ if (f == NULL) {
+ tst_resm(TWARN,
+ "Failed to open FILE '%s' at %s:%d",
+ path, file, lineno);
+ return 1;
+ }
+
+ exp_convs = count_scanf_conversions(fmt);
+
+ va_start(va, fmt);
+ ret = vfscanf(f, fmt, va);
+ va_end(va);
+
+ if (ret == EOF) {
+ tst_resm(TWARN,
+ "The FILE '%s' ended prematurely at %s:%d",
+ path, file, lineno);
+ goto err;
+ }
+
+ if (ret != exp_convs) {
+ tst_resm(TWARN,
+ "Expected %i conversions got %i FILE '%s' at %s:%d",
+ exp_convs, ret, path, file, lineno);
+ goto err;
+ }
+
+ if (fclose(f)) {
+ tst_resm(TWARN,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ return 1;
+ }
+
+ return 0;
+
+err:
+ if (fclose(f)) {
+ tst_resm(TWARN,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ }
+ return 1;
+}
+
+void safe_file_scanf(const char *file, const int lineno,
+ void (*cleanup_fn) (void),
+ const char *path, const char *fmt, ...)
+{
+ va_list va;
+ FILE *f;
+ int exp_convs, ret;
+
+ f = fopen(path, "r");
+
+ if (f == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to open FILE '%s' for reading at %s:%d",
+ path, file, lineno);
+ return;
+ }
+
+ exp_convs = count_scanf_conversions(fmt);
+
+ va_start(va, fmt);
+ ret = vfscanf(f, fmt, va);
+ va_end(va);
+
+ if (ret == EOF) {
+ tst_brkm(TBROK, cleanup_fn,
+ "The FILE '%s' ended prematurely at %s:%d",
+ path, file, lineno);
+ return;
+ }
+
+ if (ret != exp_convs) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Expected %i conversions got %i FILE '%s' at %s:%d",
+ exp_convs, ret, path, file, lineno);
+ return;
+ }
+
+ if (fclose(f)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ return;
+ }
+}
+
+
+/*
+ * Try to parse each line from file specified by 'path' according
+ * to scanf format 'fmt'. If all fields could be parsed, stop and
+ * return 0, otherwise continue or return 1 if EOF is reached.
+ */
+int file_lines_scanf(const char *file, const int lineno,
+ void (*cleanup_fn)(void), int strict,
+ const char *path, const char *fmt, ...)
+{
+ FILE *fp;
+ int ret = 0;
+ int arg_count = 0;
+ char line[BUFSIZ];
+ va_list ap;
+
+ if (!fmt) {
+ tst_brkm(TBROK, cleanup_fn, "pattern is NULL, %s:%d",
+ file, lineno);
+ return 1;
+ }
+
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to open FILE '%s' for reading at %s:%d",
+ path, file, lineno);
+ return 1;
+ }
+
+ arg_count = count_scanf_conversions(fmt);
+
+ while (fgets(line, BUFSIZ, fp) != NULL) {
+ va_start(ap, fmt);
+ ret = vsscanf(line, fmt, ap);
+ va_end(ap);
+
+ if (ret == arg_count)
+ break;
+ }
+ fclose(fp);
+
+ if (strict && ret != arg_count) {
+ tst_brkm(TBROK, cleanup_fn, "Expected %i conversions got %i"
+ " FILE '%s' at %s:%d", arg_count, ret, path, file, lineno);
+ return 1;
+ }
+
+ return !(ret == arg_count);
+}
+
+int file_printf(const char *file, const int lineno,
+ const char *path, const char *fmt, ...)
+{
+ va_list va;
+ FILE *f;
+
+ f = fopen(path, "w");
+
+ if (f == NULL) {
+ tst_resm(TWARN,
+ "Failed to open FILE '%s' at %s:%d",
+ path, file, lineno);
+ return 1;
+ }
+
+ va_start(va, fmt);
+
+ if (vfprintf(f, fmt, va) < 0) {
+ tst_resm(TWARN,
+ "Failed to print to FILE '%s' at %s:%d",
+ path, file, lineno);
+ goto err;
+ }
+
+ va_end(va);
+
+ if (fclose(f)) {
+ tst_resm(TWARN,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ return 1;
+ }
+
+ return 0;
+
+err:
+ if (fclose(f)) {
+ tst_resm(TWARN,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ }
+ return 1;
+}
+
+void safe_file_printf(const char *file, const int lineno,
+ void (*cleanup_fn) (void),
+ const char *path, const char *fmt, ...)
+{
+ va_list va;
+ FILE *f;
+
+ f = fopen(path, "w");
+
+ if (f == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to open FILE '%s' for writing at %s:%d",
+ path, file, lineno);
+ return;
+ }
+
+ va_start(va, fmt);
+
+ if (vfprintf(f, fmt, va) < 0) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Failed to print to FILE '%s' at %s:%d",
+ path, file, lineno);
+ return;
+ }
+
+ va_end(va);
+
+ if (fclose(f)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to close FILE '%s' at %s:%d",
+ path, file, lineno);
+ return;
+ }
+}
+
+//TODO: C implementation? better error condition reporting?
+void safe_cp(const char *file, const int lineno,
+ void (*cleanup_fn) (void), const char *src, const char *dst)
+{
+ size_t len = strlen(src) + strlen(dst) + 16;
+ char buf[len];
+ int ret;
+
+ snprintf(buf, sizeof(buf), "cp \"%s\" \"%s\"", src, dst);
+
+ ret = system(buf);
+
+ if (ret) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Failed to copy '%s' to '%s' at %s:%d",
+ src, dst, file, lineno);
+ }
+}
+
+#ifndef HAVE_UTIMENSAT
+
+static void set_time(struct timeval *res, const struct timespec *src,
+ long cur_tv_sec, long cur_tv_usec)
+{
+ switch (src->tv_nsec) {
+ case UTIME_NOW:
+ break;
+ case UTIME_OMIT:
+ res->tv_sec = cur_tv_sec;
+ res->tv_usec = cur_tv_usec;
+ break;
+ default:
+ res->tv_sec = src->tv_sec;
+ res->tv_usec = src->tv_nsec / 1000;
+ }
+}
+
+#endif
+
+void safe_touch(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *pathname,
+ mode_t mode, const struct timespec times[2])
+{
+ int ret;
+ mode_t defmode;
+
+ defmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+ ret = open(pathname, O_CREAT | O_WRONLY, defmode);
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to open file '%s' at %s:%d",
+ pathname, file, lineno);
+ return;
+ }
+
+ ret = close(ret);
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to close file '%s' at %s:%d",
+ pathname, file, lineno);
+ return;
+ }
+
+ if (mode != 0) {
+ ret = chmod(pathname, mode);
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to chmod file '%s' at %s:%d",
+ pathname, file, lineno);
+ return;
+ }
+ }
+
+
+#ifdef HAVE_UTIMENSAT
+ ret = utimensat(AT_FDCWD, pathname, times, 0);
+#else
+ if (times == NULL) {
+ ret = utimes(pathname, NULL);
+ } else {
+ struct stat sb;
+ struct timeval cotimes[2];
+
+ ret = stat(pathname, &sb);
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to stat file '%s' at %s:%d",
+ pathname, file, lineno);
+ return;
+ }
+
+ ret = gettimeofday(cotimes, NULL);
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to gettimeofday() at %s:%d",
+ file, lineno);
+ return;
+ }
+
+ cotimes[1] = cotimes[0];
+
+ set_time(cotimes, times,
+ sb.st_atime, sb.st_atim.tv_nsec / 1000);
+ set_time(cotimes + 1, times + 1,
+ sb.st_mtime, sb.st_mtim.tv_nsec / 1000);
+
+ ret = utimes(pathname, cotimes);
+ }
+#endif
+ if (ret == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "Failed to update the access/modification time on file"
+ " '%s' at %s:%d", pathname, file, lineno);
+ }
+}
diff --git a/src/kernel/tests/lib/safe_macros.c b/src/kernel/tests/lib/safe_macros.c
new file mode 100644
index 0000000..4f48d75
--- /dev/null
+++ b/src/kernel/tests/lib/safe_macros.c
@@ -0,0 +1,1109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Linux Test Project, 2010-2020
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+#include <sys/xattr.h>
+#include <sys/sysinfo.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include "test.h"
+#include "safe_macros.h"
+
+char *safe_basename(const char *file, const int lineno,
+ void (*cleanup_fn) (void), char *path)
+{
+ char *rval;
+
+ rval = basename(path);
+ if (rval == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: basename(%s) failed",
+ file, lineno, path);
+ }
+
+ return rval;
+}
+
+int
+safe_chdir(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *path)
+{
+ int rval;
+
+ rval = chdir(path);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: chdir(%s) failed",
+ file, lineno, path);
+ }
+
+ return rval;
+}
+
+int
+safe_close(const char *file, const int lineno, void (*cleanup_fn) (void),
+ int fildes)
+{
+ int rval;
+
+ rval = close(fildes);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: close(%d) failed",
+ file, lineno, fildes);
+ }
+
+ return rval;
+}
+
+int
+safe_creat(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *pathname, mode_t mode)
+{
+ int rval;
+
+ rval = creat(pathname, mode);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: creat(%s,0%o) failed",
+ file, lineno, pathname, mode);
+ }
+
+ return rval;
+}
+
+char *safe_dirname(const char *file, const int lineno,
+ void (*cleanup_fn) (void), char *path)
+{
+ char *rval;
+
+ rval = dirname(path);
+ if (rval == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: dirname(%s) failed",
+ file, lineno, path);
+ }
+
+ return rval;
+}
+
+char *safe_getcwd(const char *file, const int lineno, void (*cleanup_fn) (void),
+ char *buf, size_t size)
+{
+ char *rval;
+
+ rval = getcwd(buf, size);
+ if (rval == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getcwd(%p,%zu) failed",
+ file, lineno, buf, size);
+ }
+
+ return rval;
+}
+
+struct passwd *safe_getpwnam(const char *file, const int lineno,
+ void (*cleanup_fn) (void), const char *name)
+{
+ struct passwd *rval;
+
+ rval = getpwnam(name);
+ if (rval == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getpwnam(%s) failed",
+ file, lineno, name);
+ }
+
+ return rval;
+}
+
+int
+safe_getrusage(const char *file, const int lineno, void (*cleanup_fn) (void),
+ int who, struct rusage *usage)
+{
+ int rval;
+
+ rval = getrusage(who, usage);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getrusage(%d,%p) failed",
+ file, lineno, who, usage);
+ }
+
+ return rval;
+}
+
+void *safe_malloc(const char *file, const int lineno, void (*cleanup_fn) (void),
+ size_t size)
+{
+ void *rval;
+
+ rval = malloc(size);
+ if (rval == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: malloc(%zu) failed",
+ file, lineno, size);
+ }
+
+ return rval;
+}
+
+int safe_mkdir(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *pathname, mode_t mode)
+{
+ int rval;
+
+ rval = mkdir(pathname, mode);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: mkdir(%s,0%o) failed",
+ file, lineno, pathname, mode);
+ }
+
+ return (rval);
+}
+
+int safe_rmdir(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *pathname)
+{
+ int rval;
+
+ rval = rmdir(pathname);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: rmdir(%s) failed",
+ file, lineno, pathname);
+ }
+
+ return (rval);
+}
+
+int safe_munmap(const char *file, const int lineno, void (*cleanup_fn) (void),
+ void *addr, size_t length)
+{
+ int rval;
+
+ rval = munmap(addr, length);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: munmap(%p,%zu) failed",
+ file, lineno, addr, length);
+ }
+
+ return rval;
+}
+
+int safe_open(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *pathname, int oflags, ...)
+{
+ va_list ap;
+ int rval;
+ mode_t mode;
+
+ va_start(ap, oflags);
+
+ /* Android's NDK's mode_t is smaller than an int, which results in
+ * SIGILL here when passing the mode_t type.
+ */
+ mode = va_arg(ap, int);
+
+ va_end(ap);
+
+ rval = open(pathname, oflags, mode);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: open(%s,%d,0%o) failed",
+ file, lineno, pathname, oflags, mode);
+ }
+
+ return rval;
+}
+
+int safe_pipe(const char *file, const int lineno, void (*cleanup_fn) (void),
+ int fildes[2])
+{
+ int rval;
+
+ rval = pipe(fildes);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: pipe({%d,%d}) failed",
+ file, lineno, fildes[0], fildes[1]);
+ }
+
+ return rval;
+}
+
+ssize_t safe_read(const char *file, const int lineno, void (*cleanup_fn) (void),
+ char len_strict, int fildes, void *buf, size_t nbyte)
+{
+ ssize_t rval;
+
+ rval = read(fildes, buf, nbyte);
+ if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: read(%d,%p,%zu) failed, returned %zd",
+ file, lineno, fildes, buf, nbyte, rval);
+ }
+
+ return rval;
+}
+
+int safe_setegid(const char *file, const int lineno, void (*cleanup_fn) (void),
+ gid_t egid)
+{
+ int rval;
+
+ rval = setegid(egid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: setegid(%u) failed",
+ file, lineno, (unsigned) egid);
+ }
+
+ return rval;
+}
+
+int safe_seteuid(const char *file, const int lineno, void (*cleanup_fn) (void),
+ uid_t euid)
+{
+ int rval;
+
+ rval = seteuid(euid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: seteuid(%u) failed",
+ file, lineno, (unsigned) euid);
+ }
+
+ return rval;
+}
+
+int safe_setgid(const char *file, const int lineno, void (*cleanup_fn) (void),
+ gid_t gid)
+{
+ int rval;
+
+ rval = setgid(gid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: setgid(%u) failed",
+ file, lineno, (unsigned) gid);
+ }
+
+ return rval;
+}
+
+int safe_setuid(const char *file, const int lineno, void (*cleanup_fn) (void),
+ uid_t uid)
+{
+ int rval;
+
+ rval = setuid(uid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: setuid(%u) failed",
+ file, lineno, (unsigned) uid);
+ }
+
+ return rval;
+}
+
+int safe_getresuid(const char *file, const int lineno, void (*cleanup_fn)(void),
+ uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+ int rval;
+
+ rval = getresuid(ruid, euid, suid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getresuid(%p, %p, %p) failed",
+ file, lineno, ruid, euid, suid);
+ }
+
+ return rval;
+}
+
+int safe_getresgid(const char *file, const int lineno, void (*cleanup_fn)(void),
+ gid_t *rgid, gid_t *egid, gid_t *sgid)
+{
+ int rval;
+
+ rval = getresgid(rgid, egid, sgid);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getresgid(%p, %p, %p) failed",
+ file, lineno, rgid, egid, sgid);
+ }
+
+ return rval;
+}
+
+int safe_unlink(const char *file, const int lineno, void (*cleanup_fn) (void),
+ const char *pathname)
+{
+ int rval;
+
+ rval = unlink(pathname);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: unlink(%s) failed",
+ file, lineno, pathname);
+ }
+
+ return rval;
+}
+
+
+int safe_link(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *oldpath,
+ const char *newpath)
+{
+ int rval;
+
+ rval = link(oldpath, newpath);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: link(%s,%s) failed",
+ file, lineno, oldpath, newpath);
+ }
+
+ return rval;
+}
+
+int safe_linkat(const char *file, const int lineno,
+ void (cleanup_fn)(void), int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, int flags)
+{
+ int rval;
+
+ rval = linkat(olddirfd, oldpath, newdirfd, newpath, flags);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: linkat(%d,%s,%d,%s,%d) failed",
+ file, lineno, olddirfd, oldpath, newdirfd,
+ newpath, flags);
+ }
+
+ return rval;
+}
+
+ssize_t safe_readlink(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *path,
+ char *buf, size_t bufsize)
+{
+ ssize_t rval;
+
+ rval = readlink(path, buf, bufsize);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: readlink(%s,%p,%zu) failed",
+ file, lineno, path, buf, bufsize);
+ } else {
+ /* readlink does not append a NUL byte to the buffer.
+ * Add it now. */
+ if ((size_t) rval < bufsize)
+ buf[rval] = '\0';
+ else
+ buf[bufsize-1] = '\0';
+ }
+
+ return rval;
+}
+
+int safe_symlink(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *oldpath,
+ const char *newpath)
+{
+ int rval;
+
+ rval = symlink(oldpath, newpath);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: symlink(%s,%s) failed",
+ file, lineno, oldpath, newpath);
+ }
+
+ return rval;
+}
+
+ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void),
+ char len_strict, int fildes, const void *buf, size_t nbyte)
+{
+ ssize_t rval;
+
+ rval = write(fildes, buf, nbyte);
+ if (rval == -1 || (len_strict && (size_t)rval != nbyte)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: write(%d,%p,%zu) failed",
+ file, lineno, fildes, buf, rval);
+ }
+
+ return rval;
+}
+
+long safe_strtol(const char *file, const int lineno,
+ void (cleanup_fn) (void), char *str, long min, long max)
+{
+ long rval;
+ char *endptr;
+
+ errno = 0;
+ rval = strtol(str, &endptr, 10);
+
+ if ((errno == ERANGE && (rval == LONG_MAX || rval == LONG_MIN))
+ || (errno != 0 && rval == 0)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: strtol(%s) failed", file, lineno, str);
+ return rval;
+ }
+
+ if (endptr == str || (*endptr != '\0' && *endptr != '\n')) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: strtol(%s): Invalid value", file, lineno, str);
+ return 0;
+ }
+
+ if (rval > max || rval < min) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: strtol(%s): %ld is out of range %ld - %ld",
+ file, lineno, str, rval, min, max);
+ return 0;
+ }
+
+ return rval;
+}
+
+unsigned long safe_strtoul(const char *file, const int lineno,
+ void (cleanup_fn) (void), char *str,
+ unsigned long min, unsigned long max)
+{
+ unsigned long rval;
+ char *endptr;
+
+ errno = 0;
+ rval = strtoul(str, &endptr, 10);
+
+ if ((errno == ERANGE && rval == ULONG_MAX)
+ || (errno != 0 && rval == 0)) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: strtoul(%s) failed", file, lineno, str);
+ return rval;
+ }
+
+ if (rval > max || rval < min) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: strtoul(%s): %lu is out of range %lu - %lu",
+ file, lineno, str, rval, min, max);
+ return 0;
+ }
+
+ if (endptr == str || (*endptr != '\0' && *endptr != '\n')) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Invalid value: '%s' at %s:%d", str, file, lineno);
+ return 0;
+ }
+
+ return rval;
+}
+
+long safe_sysconf(const char *file, const int lineno,
+ void (cleanup_fn) (void), int name)
+{
+ long rval;
+ errno = 0;
+
+ rval = sysconf(name);
+
+ if (rval == -1) {
+ if (errno) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: sysconf(%d) failed",
+ file, lineno, name);
+ } else {
+ tst_resm(TINFO, "%s:%d: sysconf(%d): "
+ "queried option is not available"
+ " or there is no definite limit",
+ file, lineno, name);
+ }
+ }
+
+ return rval;
+}
+
+int safe_chmod(const char *file, const int lineno,
+ void (cleanup_fn)(void), const char *path, mode_t mode)
+{
+ int rval;
+
+ rval = chmod(path, mode);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: chmod(%s,0%o) failed",
+ file, lineno, path, mode);
+ }
+
+ return rval;
+}
+
+int safe_fchmod(const char *file, const int lineno,
+ void (cleanup_fn)(void), int fd, mode_t mode)
+{
+ int rval;
+
+ rval = fchmod(fd, mode);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: fchmod(%d,0%o) failed",
+ file, lineno, fd, mode);
+ }
+
+ return rval;
+}
+
+int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, uid_t owner, gid_t group)
+{
+ int rval;
+
+ rval = chown(path, owner, group);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: chown(%s,%d,%d) failed",
+ file, lineno, path, owner, group);
+ }
+
+ return rval;
+}
+
+int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void),
+ int fd, uid_t owner, gid_t group)
+{
+ int rval;
+
+ rval = fchown(fd, owner, group);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: fchown(%d,%d,%d) failed",
+ file, lineno, fd, owner, group);
+ }
+
+ return rval;
+}
+
+pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void),
+ int *status)
+{
+ pid_t rval;
+
+ rval = wait(status);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: wait(%p) failed",
+ file, lineno, status);
+ }
+
+ return rval;
+}
+
+pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void),
+ pid_t pid, int *status, int opts)
+{
+ pid_t rval;
+
+ rval = waitpid(pid, status, opts);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: waitpid(%d,%p,%d) failed",
+ file, lineno, pid, status, opts);
+ }
+
+ return rval;
+}
+
+void *safe_memalign(const char *file, const int lineno,
+ void (*cleanup_fn) (void), size_t alignment, size_t size)
+{
+ void *rval;
+
+ rval = memalign(alignment, size);
+ if (rval == NULL)
+ tst_brkm(TBROK | TERRNO, cleanup_fn, "memalign failed at %s:%d",
+ file, lineno);
+
+ return rval;
+}
+
+int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void),
+ pid_t pid, int sig)
+{
+ int rval;
+
+ rval = kill(pid, sig);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: kill(%d,%s) failed",
+ file, lineno, pid, tst_strsig(sig));
+ }
+
+ return rval;
+}
+
+int safe_mkfifo(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *pathname, mode_t mode)
+{
+ int rval;
+
+ rval = mkfifo(pathname, mode);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: mkfifo(%s, 0%o) failed",
+ file, lineno, pathname, mode);
+ }
+
+ return rval;
+}
+
+int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *oldpath, const char *newpath)
+{
+ int rval;
+
+ rval = rename(oldpath, newpath);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: rename(%s, %s) failed",
+ file, lineno, oldpath, newpath);
+ }
+
+ return rval;
+}
+
+static const char *const fuse_fs_types[] = {
+ "exfat",
+ "ntfs",
+};
+
+static int possibly_fuse(const char *fs_type)
+{
+ unsigned int i;
+
+ if (!fs_type)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(fuse_fs_types); i++) {
+ if (!strcmp(fuse_fs_types[i], fs_type))
+ return 1;
+ }
+
+ return 0;
+}
+
+int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *source, const char *target,
+ const char *filesystemtype, unsigned long mountflags,
+ const void *data)
+{
+ int rval;
+
+ /*
+ * Don't try using the kernel's NTFS driver when mounting NTFS, since
+ * the kernel's NTFS driver doesn't have proper write support.
+ */
+ if (!filesystemtype || strcmp(filesystemtype, "ntfs")) {
+ rval = mount(source, target, filesystemtype, mountflags, data);
+ if (!rval)
+ return 0;
+ }
+
+ /*
+ * The FUSE filesystem executes mount.fuse helper, which tries to
+ * execute corresponding binary name which is encoded at the start of
+ * the source string and separated by # from the device name.
+ *
+ * The mount helpers are called mount.$fs_type.
+ */
+ if (possibly_fuse(filesystemtype)) {
+ char buf[1024];
+
+ tst_resm(TINFO, "Trying FUSE...");
+ snprintf(buf, sizeof(buf), "mount.%s '%s' '%s'",
+ filesystemtype, source, target);
+
+ rval = tst_system(buf);
+ if (WIFEXITED(rval) && WEXITSTATUS(rval) == 0)
+ return 0;
+
+ tst_brkm(TBROK, cleanup_fn, "mount.%s failed with %i",
+ filesystemtype, rval);
+ return -1;
+ } else {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: mount(%s, %s, %s, %lu, %p) failed",
+ file, lineno, source, target, filesystemtype,
+ mountflags, data);
+ }
+
+ return -1;
+}
+
+int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void),
+ const char *target)
+{
+ int rval;
+
+ rval = tst_umount(target);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: umount(%s) failed",
+ file, lineno, target);
+ }
+
+ return rval;
+}
+
+DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *name)
+{
+ DIR *rval;
+
+ rval = opendir(name);
+
+ if (!rval) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: opendir(%s) failed", file, lineno, name);
+ }
+
+ return rval;
+}
+
+int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void),
+ DIR *dirp)
+{
+ int rval;
+
+ rval = closedir(dirp);
+
+ if (rval) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: closedir(%p) failed", file, lineno, dirp);
+ }
+
+ return rval;
+}
+
+struct dirent *safe_readdir(const char *file, const int lineno, void (cleanup_fn)(void),
+ DIR *dirp)
+{
+ struct dirent *rval;
+ int err = errno;
+
+ errno = 0;
+ rval = readdir(dirp);
+
+ if (!rval && errno) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: readdir(%p) failed", file, lineno, dirp);
+ }
+
+ errno = err;
+ return rval;
+}
+
+int safe_getpriority(const char *file, const int lineno, int which, id_t who)
+{
+ int rval, err = errno;
+
+ errno = 0;
+ rval = getpriority(which, who);
+ if (errno) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d getpriority(%i, %i) failed",
+ file, lineno, which, who);
+ }
+
+ errno = err;
+ return rval;
+}
+
+ssize_t safe_getxattr(const char *file, const int lineno, const char *path,
+ const char *name, void *value, size_t size)
+{
+ ssize_t rval;
+
+ rval = getxattr(path, name, value, size);
+
+ if (rval == -1) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: getxattr(%s, %s, %p, %zu) failed",
+ file, lineno, path, name, value, size);
+ }
+
+ return rval;
+}
+
+int safe_setxattr(const char *file, const int lineno, const char *path,
+ const char *name, const void *value, size_t size, int flags)
+{
+ int rval;
+
+ rval = setxattr(path, name, value, size, flags);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: setxattr(%s, %s, %p, %zu) failed",
+ file, lineno, path, name, value, size);
+ }
+
+ return rval;
+}
+
+int safe_lsetxattr(const char *file, const int lineno, const char *path,
+ const char *name, const void *value, size_t size, int flags)
+{
+ int rval;
+
+ rval = lsetxattr(path, name, value, size, flags);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: lsetxattr(%s, %s, %p, %zu, %i) failed",
+ file, lineno, path, name, value, size, flags);
+ }
+
+ return rval;
+}
+
+int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name,
+ const void *value, size_t size, int flags)
+{
+ int rval;
+
+ rval = fsetxattr(fd, name, value, size, flags);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: fsetxattr(%i, %s, %p, %zu, %i) failed",
+ file, lineno, fd, name, value, size, flags);
+ }
+
+ return rval;
+}
+
+int safe_removexattr(const char *file, const int lineno, const char *path,
+ const char *name)
+{
+ int rval;
+
+ rval = removexattr(path, name);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: removexattr(%s, %s) failed",
+ file, lineno, path, name);
+ }
+
+ return rval;
+}
+
+int safe_lremovexattr(const char *file, const int lineno, const char *path,
+ const char *name)
+{
+ int rval;
+
+ rval = lremovexattr(path, name);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: lremovexattr(%s, %s) failed",
+ file, lineno, path, name);
+ }
+
+ return rval;
+}
+
+int safe_fremovexattr(const char *file, const int lineno, int fd,
+ const char *name)
+{
+ int rval;
+
+ rval = fremovexattr(fd, name);
+
+ if (rval) {
+ if (errno == ENOTSUP) {
+ tst_brkm(TCONF, NULL,
+ "%s:%d: no xattr support in fs or mounted "
+ "without user_xattr option", file, lineno);
+ }
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: fremovexattr(%i, %s) failed",
+ file, lineno, fd, name);
+ }
+
+ return rval;
+}
+
+int safe_fsync(const char *file, const int lineno, int fd)
+{
+ int rval;
+
+ rval = fsync(fd);
+
+ if (rval) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: fsync(%i) failed", file, lineno, fd);
+ }
+
+ return rval;
+}
+
+pid_t safe_setsid(const char *file, const int lineno)
+{
+ pid_t rval;
+
+ rval = setsid();
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: setsid() failed", file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_mknod(const char *file, const int lineno, const char *pathname,
+ mode_t mode, dev_t dev)
+{
+ int rval;
+
+ rval = mknod(pathname, mode, dev);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: mknod() failed", file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_mlock(const char *file, const int lineno, const void *addr,
+ size_t len)
+{
+ int rval;
+
+ rval = mlock(addr, len);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: mlock() failed", file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_munlock(const char *file, const int lineno, const void *addr,
+ size_t len)
+{
+ int rval;
+
+ rval = munlock(addr, len);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: munlock() failed", file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_mincore(const char *file, const int lineno, void *start,
+ size_t length, unsigned char *vec)
+{
+ int rval;
+
+ rval = mincore(start, length, vec);
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: mincore() failed", file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info)
+{
+ int ret;
+
+ errno = 0;
+ ret = sysinfo(info);
+
+ if (ret == -1) {
+ tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
+ "sysinfo() failed");
+ } else if (ret) {
+ tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
+ "Invalid sysinfo() return value %d", ret);
+ }
+
+ return ret;
+}
diff --git a/src/kernel/tests/lib/safe_net.c b/src/kernel/tests/lib/safe_net.c
new file mode 100644
index 0000000..4993680
--- /dev/null
+++ b/src/kernel/tests/lib/safe_net.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2015 Fujitsu Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <errno.h>
+#include "test.h"
+#include "safe_net_fn.h"
+
+char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res,
+ size_t len)
+{
+ char portstr[8];
+
+ switch (sa->sa_family) {
+
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if (!inet_ntop(AF_INET, &sin->sin_addr, res, len))
+ return NULL;
+
+ if (ntohs(sin->sin_port) != 0) {
+ snprintf(portstr, sizeof(portstr), ":%d",
+ ntohs(sin->sin_port));
+ strcat(res, portstr);
+ }
+
+ return res;
+ }
+
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ res[0] = '[';
+ if (!inet_ntop(AF_INET6, &sin6->sin6_addr, res + 1, len - 1))
+ return NULL;
+
+ if (ntohs(sin6->sin6_port) != 0) {
+ snprintf(portstr, sizeof(portstr), "]:%d",
+ ntohs(sin6->sin6_port));
+ strcat(res, portstr);
+ return res;
+ }
+
+ return res + 1;
+ }
+
+ case AF_UNIX: {
+ struct sockaddr_un *unp = (struct sockaddr_un *)sa;
+
+ if (unp->sun_path[0] == '\0')
+ strcpy(res, "(no pathname bound)");
+ else
+ snprintf(res, len, "%s", unp->sun_path);
+
+ return res;
+ }
+
+ default: {
+ snprintf(res, len,
+ "sock_ntop: unknown AF_xxx: %d, len: %d",
+ sa->sa_family, salen);
+
+ return res;
+ }
+
+ }
+}
+
+int tst_getsockport(const char *file, const int lineno, int sockfd)
+{
+ struct sockaddr_storage ss;
+ socklen_t addrlen = sizeof(ss);
+ struct sockaddr *sa = (struct sockaddr *)&ss;
+
+ safe_getsockname(file, lineno, NULL, sockfd, sa, &addrlen);
+
+ switch (sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ return ntohs(sin->sin_port);
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ return ntohs(sin6->sin6_port);
+ } }
+
+ return -1;
+}
+
+int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
+ int domain, int type, int protocol)
+{
+ int rval, ttype;
+
+ rval = socket(domain, type, protocol);
+
+ if (rval < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+ case ESOCKTNOSUPPORT:
+ case EOPNOTSUPP:
+ case EPFNOSUPPORT:
+ case EAFNOSUPPORT:
+ ttype = TCONF;
+ break;
+ default:
+ ttype = TBROK;
+ }
+
+ tst_brkm(ttype | TERRNO, cleanup_fn,
+ "%s:%d: socket(%d, %d, %d) failed", file, lineno,
+ domain, type, protocol);
+ }
+
+ return rval;
+}
+
+int safe_socketpair(const char *file, const int lineno, int domain, int type,
+ int protocol, int sv[])
+{
+ int rval, ttype;
+
+ rval = socketpair(domain, type, protocol, sv);
+
+ if (rval < 0) {
+ switch (errno) {
+ case EPROTONOSUPPORT:
+ case EOPNOTSUPP:
+ case EAFNOSUPPORT:
+ ttype = TCONF;
+ break;
+ default:
+ ttype = TBROK;
+ }
+
+ tst_brkm(ttype | TERRNO, NULL,
+ "%s:%d: socketpair(%d, %d, %d, %p) failed",
+ file, lineno, domain, type, protocol, sv);
+ }
+
+ return rval;
+}
+
+int safe_getsockopt(const char *file, const int lineno, int sockfd, int level,
+ int optname, void *optval, socklen_t *optlen)
+{
+ int rval = getsockopt(sockfd, level, optname, optval, optlen);
+
+ if (!rval)
+ return 0;
+
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: getsockopt(%d, %d, %d, %p, %p) failed",
+ file, lineno, sockfd, level, optname, optval, optlen);
+
+ return rval;
+}
+
+int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
+ int optname, const void *optval, socklen_t optlen)
+{
+ int rval;
+
+ rval = setsockopt(sockfd, level, optname, optval, optlen);
+
+ if (rval) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: setsockopt(%d, %d, %d, %p, %d) failed",
+ file, lineno, sockfd, level, optname, optval, optlen);
+ }
+
+ return rval;
+}
+
+ssize_t safe_send(const char *file, const int lineno, char len_strict,
+ int sockfd, const void *buf, size_t len, int flags)
+{
+ ssize_t rval;
+
+ rval = send(sockfd, buf, len, flags);
+
+ if (rval == -1 || (len_strict && (size_t)rval != len)) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: send(%d, %p, %zu, %d) failed",
+ file, lineno, sockfd, buf, len, flags);
+ }
+
+ return rval;
+}
+
+ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
+ int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen)
+{
+ ssize_t rval;
+ char res[128];
+
+ rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
+
+ if (rval == -1 || (len_strict && (size_t)rval != len)) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: sendto(%d, %p, %zu, %d, %s, %d) failed",
+ file, lineno, sockfd, buf, len, flags,
+ tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
+ addrlen);
+ }
+
+ return rval;
+}
+
+ssize_t safe_sendmsg(const char *file, const int lineno, size_t len,
+ int sockfd, const struct msghdr *msg, int flags)
+{
+ ssize_t rval;
+
+ rval = sendmsg(sockfd, msg, flags);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: sendmsg(%d, %p, %d) failed",
+ file, lineno, sockfd, msg, flags);
+ }
+
+ if (len && (size_t)rval != len) {
+ tst_brkm(TBROK, NULL,
+ "%s:%d: sendmsg(%d, %p, %d) ret(%zd) != len(%zu)",
+ file, lineno, sockfd, msg, flags, rval, len);
+ }
+
+ return rval;
+}
+
+ssize_t safe_recvmsg(const char *file, const int lineno, size_t len,
+ int sockfd, struct msghdr *msg, int flags)
+{
+ ssize_t rval;
+
+ rval = recvmsg(sockfd, msg, flags);
+
+ if (rval == -1) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: recvmsg(%d, %p, %d) failed",
+ file, lineno, sockfd, msg, flags);
+ }
+
+ if (len && (size_t)rval != len) {
+ tst_brkm(TBROK, NULL,
+ "%s:%d: recvmsg(%d, %p, %d) ret(%zd) != len(%zu)",
+ file, lineno, sockfd, msg, flags, rval, len);
+ }
+
+ return rval;
+
+}
+
+int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
+ int socket, const struct sockaddr *address,
+ socklen_t address_len)
+{
+ int i;
+ char buf[128];
+
+ for (i = 0; i < 120; i++) {
+ if (!bind(socket, address, address_len))
+ return 0;
+
+ if (errno != EADDRINUSE) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: bind(%d, %s, %d) failed", file, lineno,
+ socket, tst_sock_addr(address, address_len,
+ buf, sizeof(buf)),
+ address_len);
+ return -1;
+ }
+
+ if ((i + 1) % 10 == 0) {
+ tst_resm(TINFO, "address is in use, waited %3i sec",
+ i + 1);
+ }
+
+ sleep(1);
+ }
+
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: Failed to bind(%d, %s, %d) after 120 retries", file,
+ lineno, socket,
+ tst_sock_addr(address, address_len, buf, sizeof(buf)),
+ address_len);
+ return -1;
+}
+
+int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
+ int socket, int backlog)
+{
+ int rval;
+
+ rval = listen(socket, backlog);
+
+ if (rval < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: listen(%d, %d) failed", file, lineno, socket,
+ backlog);
+ }
+
+ return rval;
+}
+
+int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void),
+ int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ int rval;
+
+ rval = accept(sockfd, addr, addrlen);
+
+ if (rval < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: accept(%d, %p, %d) failed", file, lineno,
+ sockfd, addr, *addrlen);
+ }
+
+ return rval;
+}
+
+int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
+ int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ int rval;
+ char buf[128];
+
+ rval = connect(sockfd, addr, addrlen);
+
+ if (rval < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: connect(%d, %s, %d) failed", file, lineno,
+ sockfd, tst_sock_addr(addr, addrlen, buf,
+ sizeof(buf)), addrlen);
+ }
+
+ return rval;
+}
+
+int safe_getsockname(const char *file, const int lineno,
+ void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
+ socklen_t *addrlen)
+{
+ int rval;
+ char buf[128];
+
+ rval = getsockname(sockfd, addr, addrlen);
+
+ if (rval < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getsockname(%d, %s, %d) failed", file, lineno,
+ sockfd, tst_sock_addr(addr, *addrlen, buf,
+ sizeof(buf)), *addrlen);
+ }
+
+ return rval;
+}
+
+int safe_gethostname(const char *file, const int lineno,
+ char *name, size_t size)
+{
+ int rval = gethostname(name, size);
+
+ if (rval < 0) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s:%d: gethostname(%p, %zu) failed",
+ file, lineno, name, size);
+ }
+
+ return rval;
+}
+
+/*
+ * @return port in network byte order.
+ */
+unsigned short tst_get_unused_port(const char *file, const int lineno,
+ void (cleanup_fn)(void), unsigned short family, int type)
+{
+ int sock;
+ socklen_t slen;
+ struct sockaddr_storage _addr;
+ struct sockaddr *addr = (struct sockaddr *)&_addr;
+ struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
+
+ switch (family) {
+ case AF_INET:
+ addr4->sin_family = AF_INET;
+ addr4->sin_port = 0;
+ addr4->sin_addr.s_addr = INADDR_ANY;
+ slen = sizeof(*addr4);
+ break;
+
+ case AF_INET6:
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = 0;
+ addr6->sin6_addr = in6addr_any;
+ slen = sizeof(*addr6);
+ break;
+
+ default:
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: unknown family", file, lineno);
+ return -1;
+ }
+
+ sock = socket(addr->sa_family, type, 0);
+ if (sock < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: socket failed", file, lineno);
+ return -1;
+ }
+
+ if (bind(sock, addr, slen) < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: bind failed", file, lineno);
+ return -1;
+ }
+
+ if (getsockname(sock, addr, &slen) == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: getsockname failed", file, lineno);
+ return -1;
+ }
+
+ if (close(sock) == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: close failed", file, lineno);
+ return -1;
+ }
+
+ switch (family) {
+ case AF_INET:
+ return addr4->sin_port;
+ case AF_INET6:
+ return addr6->sin6_port;
+ default:
+ return -1;
+ }
+}
diff --git a/src/kernel/tests/lib/safe_pthread.c b/src/kernel/tests/lib/safe_pthread.c
new file mode 100644
index 0000000..2866aa5
--- /dev/null
+++ b/src/kernel/tests/lib/safe_pthread.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+int safe_pthread_create(const char *file, const int lineno,
+ pthread_t *thread_id, const pthread_attr_t *attr,
+ void *(*thread_fn)(void *), void *arg)
+{
+ int rval;
+
+ rval = pthread_create(thread_id, attr, thread_fn, arg);
+
+ if (rval) {
+ tst_brk_(file, lineno, TBROK,
+ "pthread_create(%p,%p,%p,%p) failed: %s", thread_id,
+ attr, thread_fn, arg, tst_strerrno(rval));
+ }
+
+ return rval;
+}
+
+int safe_pthread_join(const char *file, const int lineno,
+ pthread_t thread_id, void **retval)
+{
+ int rval;
+
+ rval = pthread_join(thread_id, retval);
+
+ if (rval) {
+ tst_brk_(file, lineno, TBROK,
+ "pthread_join(..., %p) failed: %s",
+ retval, tst_strerrno(rval));
+ }
+
+ return rval;
+}
diff --git a/src/kernel/tests/lib/safe_stdio.c b/src/kernel/tests/lib/safe_stdio.c
new file mode 100644
index 0000000..966a039
--- /dev/null
+++ b/src/kernel/tests/lib/safe_stdio.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include "test.h"
+#include "safe_stdio_fn.h"
+
+FILE *safe_fopen(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *path, const char *mode)
+{
+ FILE *f = fopen(path, mode);
+
+ if (f == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: fopen(%s,%s) failed",
+ file, lineno, path, mode);
+ }
+
+ return f;
+}
+
+int safe_fclose(const char *file, const int lineno, void (cleanup_fn)(void),
+ FILE *f)
+{
+ int ret;
+
+ ret = fclose(f);
+
+ if (ret) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: fclose(%p) failed", file, lineno, f);
+ }
+
+ return ret;
+}
+
+int safe_asprintf(const char *file, const int lineno, void (cleanup_fn)(void),
+ char **strp, const char *fmt, ...)
+{
+ int ret;
+ va_list va;
+
+ va_start(va, fmt);
+ ret = vasprintf(strp, fmt, va);
+ va_end(va);
+
+ if (ret < 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: asprintf(%s,...) failed", file, lineno, fmt);
+ }
+
+ return ret;
+}
+
+FILE *safe_popen(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *command, const char *type)
+{
+ FILE *stream;
+ const int saved_errno = errno;
+
+ errno = 0;
+ stream = popen(command, type);
+
+ if (stream == NULL) {
+ if (errno != 0) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: popen(%s,%s) failed",
+ file, lineno, command, type);
+ } else {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: popen(%s,%s) failed: Out of memory",
+ file, lineno, command, type);
+ }
+ }
+
+ errno = saved_errno;
+
+ return stream;
+}
diff --git a/src/kernel/tests/lib/self_exec.c b/src/kernel/tests/lib/self_exec.c
new file mode 100644
index 0000000..de7d095
--- /dev/null
+++ b/src/kernel/tests/lib/self_exec.c
@@ -0,0 +1,225 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: t -*- */
+/*
+ * self_exec.c: self_exec magic required to run child functions on uClinux
+ *
+ * Copyright (C) 2005 Paul J.Y. Lahaie <pjlahaie-at-steamballoon.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This software was produced by Steamballoon Incorporated
+ * 55 Byward Market Square, 2nd Floor North, Ottawa, ON K1N 9C3, Canada
+ */
+
+#define _GNU_SOURCE /* for asprintf */
+
+#include "config.h"
+
+#ifdef UCLINUX
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include "test.h"
+#include "safe_macros.h"
+
+/* Set from parse_opts.c: */
+char *child_args; /* Arguments to child when -C is used */
+
+static char *start_cwd; /* Stores the starting directory for self_exec */
+
+int asprintf(char **app, const char *fmt, ...)
+{
+ va_list ptr;
+ int rv;
+ char *p;
+
+ /*
+ * First iteration - find out size of buffer required and allocate it.
+ */
+ va_start(ptr, fmt);
+ rv = vsnprintf(NULL, 0, fmt, ptr);
+ va_end(ptr);
+
+ p = malloc(++rv); /* allocate the buffer */
+ *app = p;
+ if (!p) {
+ return -1;
+ }
+
+ /*
+ * Second iteration - actually produce output.
+ */
+ va_start(ptr, fmt);
+ rv = vsnprintf(p, rv, fmt, ptr);
+ va_end(ptr);
+
+ return rv;
+}
+
+void maybe_run_child(void (*child) (), const char *fmt, ...)
+{
+ va_list ap;
+ char *child_dir;
+ char *p, *tok;
+ int *iptr, i, j;
+ char *s;
+ char **sptr;
+ char *endptr;
+
+ /* Store the current directory for later use. */
+ start_cwd = getcwd(NULL, 0);
+
+ if (child_args) {
+ char *args = strdup(child_args);
+
+ child_dir = strtok(args, ",");
+ if (strlen(child_dir) == 0) {
+ tst_brkm(TBROK, NULL,
+ "Could not get directory from -C option");
+ return;
+ }
+
+ va_start(ap, fmt);
+
+ for (p = fmt; *p; p++) {
+ tok = strtok(NULL, ",");
+ if (!tok || strlen(tok) == 0) {
+ tst_brkm(TBROK, NULL,
+ "Invalid argument to -C option");
+ return;
+ }
+
+ switch (*p) {
+ case 'd':
+ iptr = va_arg(ap, int *);
+ i = strtol(tok, &endptr, 10);
+ if (*endptr != '\0') {
+ tst_brkm(TBROK, NULL,
+ "Invalid argument to -C option");
+ return;
+ }
+ *iptr = i;
+ break;
+ case 'n':
+ j = va_arg(ap, int);
+ i = strtol(tok, &endptr, 10);
+ if (*endptr != '\0') {
+ tst_brkm(TBROK, NULL,
+ "Invalid argument to -C option");
+ return;
+ }
+ if (j != i) {
+ va_end(ap);
+ free(args);
+ return;
+ }
+ break;
+ case 's':
+ s = va_arg(ap, char *);
+ if (!strncpy(s, tok, strlen(tok) + 1)) {
+ tst_brkm(TBROK, NULL,
+ "Could not strncpy for -C option");
+ return;
+ }
+ break;
+ case 'S':
+ sptr = va_arg(ap, char **);
+ *sptr = strdup(tok);
+ if (!*sptr) {
+ tst_brkm(TBROK, NULL,
+ "Could not strdup for -C option");
+ return;
+ }
+ break;
+ default:
+ tst_brkm(TBROK, NULL,
+ "Format string option %c not implemented",
+ *p);
+ return;
+ }
+ }
+
+ va_end(ap);
+ free(args);
+ SAFE_CHDIR(NULL, child_dir);
+
+ (*child) ();
+ tst_resm(TWARN, "Child function returned unexpectedly");
+ /* Exit here? or exit silently? */
+ }
+}
+
+int self_exec(const char *argv0, const char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+ char *tmp_cwd;
+ char *arg;
+ int ival;
+ char *str;
+
+ if ((tmp_cwd = getcwd(NULL, 0)) == NULL) {
+ tst_resm(TBROK, "Could not getcwd()");
+ return -1;
+ }
+
+ arg = strdup(tmp_cwd);
+ if (arg == NULL) {
+ tst_resm(TBROK, "Could not produce self_exec string");
+ return -1;
+ }
+
+ va_start(ap, fmt);
+
+ for (p = fmt; *p; p++) {
+ switch (*p) {
+ case 'd':
+ case 'n':
+ ival = va_arg(ap, int);
+ if (asprintf(&arg, "%s,%d", arg, ival) < 0) {
+ tst_resm(TBROK,
+ "Could not produce self_exec string");
+ return -1;
+ }
+ break;
+ case 's':
+ case 'S':
+ str = va_arg(ap, char *);
+ if (asprintf(&arg, "%s,%s", arg, str) < 0) {
+ tst_resm(TBROK,
+ "Could not produce self_exec string");
+ return -1;
+ }
+ break;
+ default:
+ tst_resm(TBROK,
+ "Format string option %c not implemented", *p);
+ return -1;
+ break;
+ }
+ }
+
+ va_end(ap);
+
+ if (chdir(start_cwd) < 0) {
+ tst_resm(TBROK, "Could not change to %s for self_exec",
+ start_cwd);
+ return -1;
+ }
+
+ return execlp(argv0, argv0, "-C", arg, (char *)NULL);
+}
+
+#endif /* UCLINUX */
diff --git a/src/kernel/tests/lib/signame.h b/src/kernel/tests/lib/signame.h
new file mode 100644
index 0000000..d420458
--- /dev/null
+++ b/src/kernel/tests/lib/signame.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014 Fujitsu Ltd.
+ * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+const char *tst_strsig(int sig)
+{
+ static const struct pair signal_pairs[] = {
+ PAIR(SIGHUP)
+ PAIR(SIGINT)
+ PAIR(SIGQUIT)
+ PAIR(SIGILL)
+ #ifdef SIGTRAP
+ PAIR(SIGTRAP)
+ #endif
+
+ #ifdef SIGIOT
+ /* SIGIOT same as SIGABRT */
+ STRPAIR(SIGABRT, "SIGIOT/SIGABRT")
+ #else
+ PAIR(SIGABRT)
+ #endif
+
+ #ifdef SIGEMT
+ PAIR(SIGEMT)
+ #endif
+ #ifdef SIGBUS
+ PAIR(SIGBUS)
+ #endif
+ PAIR(SIGFPE)
+ PAIR(SIGKILL)
+ PAIR(SIGUSR1)
+ PAIR(SIGSEGV)
+ PAIR(SIGUSR2)
+ PAIR(SIGPIPE)
+ PAIR(SIGALRM)
+ PAIR(SIGTERM)
+ #ifdef SIGSTKFLT
+ PAIR(SIGSTKFLT)
+ #endif
+ PAIR(SIGCHLD)
+ PAIR(SIGCONT)
+ PAIR(SIGSTOP)
+ PAIR(SIGTSTP)
+ PAIR(SIGTTIN)
+ PAIR(SIGTTOU)
+ #ifdef SIGURG
+ PAIR(SIGURG)
+ #endif
+ #ifdef SIGXCPU
+ PAIR(SIGXCPU)
+ #endif
+ #ifdef SIGXFSZ
+ PAIR(SIGXFSZ)
+ #endif
+ #ifdef SIGVTALRM
+ PAIR(SIGVTALRM)
+ #endif
+ #ifdef SIGPROF
+ PAIR(SIGPROF)
+ #endif
+ #ifdef SIGWINCH
+ PAIR(SIGWINCH)
+ #endif
+
+ #if defined(SIGIO) && defined(SIGPOLL)
+ /* SIGPOLL same as SIGIO */
+ STRPAIR(SIGIO, "SIGIO/SIGPOLL")
+ #elif defined(SIGIO)
+ PAIR(SIGIO)
+ #elif defined(SIGPOLL)
+ PAIR(SIGPOLL)
+ #endif
+
+ #ifdef SIGINFO
+ PAIR(SIGINFO)
+ #endif
+ #ifdef SIGLOST
+ PAIR(SIGLOST)
+ #endif
+ #ifdef SIGPWR
+ PAIR(SIGPWR)
+ #endif
+ #if defined(SIGSYS)
+ /*
+ * According to signal(7)'s manpage, SIGUNUSED is synonymous
+ * with SIGSYS on most architectures.
+ */
+ STRPAIR(SIGSYS, "SIGSYS/SIGUNUSED")
+ #endif
+ };
+
+ PAIR_LOOKUP(signal_pairs, sig);
+};
diff --git a/src/kernel/tests/lib/tlibio.c b/src/kernel/tests/lib/tlibio.c
new file mode 100644
index 0000000..cc110d1
--- /dev/null
+++ b/src/kernel/tests/lib/tlibio.c
@@ -0,0 +1,2161 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ *
+ * Lib i/o
+ *
+ * This file contains several functions to doing reads and writes.
+ * It was written so that a single function could be called in a test
+ * program and only a io type field value would have to change to
+ * do different types of io. There is even a couple of functions that
+ * will allow you to parse a string to determine the iotype.
+ *
+ * This file contains functions for writing/reading to/from open files
+ * Prototypes:
+ *
+ * Functions declared in this module - see individual function code for
+ * usage comments:
+ *
+ * int stride_bounds(int offset, int stride, int nstrides,
+ * int bytes_per_stride, int *min, int *max);
+
+ * int lio_write_buffer(int fd, int method, char *buffer, int size,
+ * char **errmsg, long wrd);
+ * int lio_read_buffer(int fd, int method, char *buffer, int size,
+ * char **errmsg, long wrd);
+ *
+ * #ifdef CRAY
+ * int lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+ * int lio_check_asyncio(char *io_type, int size, struct iosw *status)
+ * #endif
+ * #ifdef sgi
+ * int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
+ * int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
+ * #endif
+ *
+ * int lio_parse_io_arg1(char *string)
+ * void lio_help1(char *prefix);
+ *
+ * int lio_parse_io_arg2(char *string, char **badtoken)
+ * void lio_help2(char *prefix);
+ *
+ * int lio_set_debug(int level);
+ *
+ * char Lio_SysCall[];
+ * struct lio_info_type Lio_info1[];
+ * struct lio_info_type Lio_info2[];
+ *
+ * Author : Richard Logan
+ *
+ */
+
+#ifdef __linux__
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _LARGEFILE64_SOURCE
+#endif
+#include "config.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <stdint.h>
+#ifdef CRAY
+#include <sys/secparm.h>
+#include <sys/iosw.h>
+#include <sys/listio.h>
+#else
+/* for linux or sgi */
+#include <sys/uio.h> /* readv(2)/writev(2) */
+#include <string.h>
+#endif
+#if defined(__linux__) || defined(__sun) || defined(__hpux) || defined(_AIX)
+#if !defined(UCLINUX) && !defined(__UCLIBC__)
+#include <aio.h>
+#endif
+#endif
+#include <stdlib.h> /* atoi, abs */
+
+#include "tlibio.h" /* defines LIO* marcos */
+#include "random_range.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#if 0 /* disabled until it's needed -- roehrich 6/11/97 */
+#define BUG1_workaround 1 /* Work around a condition where aio_return gives
+ * a value of zero but there is no errno followup
+ * and the read/write operation actually did its
+ * job. spr/pv 705244
+ */
+#endif
+
+
+/*
+ * Define the structure as used in lio_parse_arg1 and lio_help1
+ */
+struct lio_info_type Lio_info1[] = {
+ {"s", LIO_IO_SYNC, "sync i/o"},
+ {"p", LIO_IO_ASYNC | LIO_WAIT_SIGACTIVE,
+ "async i/o using a loop to wait for a signal"},
+ {"b", LIO_IO_ASYNC | LIO_WAIT_SIGPAUSE, "async i/o using pause"},
+ {"a", LIO_IO_ASYNC | LIO_WAIT_RECALL,
+ "async i/o using recall/aio_suspend"},
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ {"r",
+ LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES,
+ "random sync i/o types and wait methods"},
+ {"R",
+ LIO_RANDOM | LIO_IO_ATYPES | LIO_WAIT_ATYPES,
+ "random i/o types and wait methods"},
+#else
+ {"r",
+ LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES,
+ "random i/o types and wait methods"},
+ {"R",
+ LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES,
+ "random i/o types and wait methods"},
+#endif
+ {"l", LIO_IO_SLISTIO | LIO_WAIT_RECALL, "single stride sync listio"},
+ {"L", LIO_IO_ALISTIO | LIO_WAIT_RECALL,
+ "single stride async listio using recall"},
+ {"X", LIO_IO_ALISTIO | LIO_WAIT_SIGPAUSE,
+ "single stride async listio using pause"},
+ {"v", LIO_IO_SYNCV, "single buffer sync readv/writev"},
+ {"P", LIO_IO_SYNCP, "sync pread/pwrite"},
+};
+
+/*
+ * Define the structure used by lio_parse_arg2 and lio_help2
+ */
+struct lio_info_type Lio_info2[] = {
+ {"sync", LIO_IO_SYNC, "sync i/o (read/write)"},
+ {"async", LIO_IO_ASYNC, "async i/o (reada/writea/aio_read/aio_write)"},
+ {"slistio", LIO_IO_SLISTIO, "single stride sync listio"},
+ {"alistio", LIO_IO_ALISTIO, "single stride async listio"},
+ {"syncv", LIO_IO_SYNCV, "single buffer sync readv/writev"},
+ {"syncp", LIO_IO_SYNCP, "pread/pwrite"},
+ {"active", LIO_WAIT_ACTIVE, "spin on status/control values"},
+ {"recall", LIO_WAIT_RECALL,
+ "use recall(2)/aio_suspend(3) to wait for i/o to complete"},
+ {"sigactive", LIO_WAIT_SIGACTIVE, "spin waiting for signal"},
+ {"sigpause", LIO_WAIT_SIGPAUSE, "call pause(2) to wait for signal"},
+/* nowait is a touchy thing, it's an accident that this implementation worked at all. 6/27/97 roehrich */
+/* { "nowait", LIO_WAIT_NONE, "do not wait for async io to complete" },*/
+ {"random", LIO_RANDOM, "set random bit"},
+ {"randomall",
+ LIO_RANDOM | LIO_IO_TYPES | LIO_WAIT_TYPES,
+ "all random i/o types and wait methods (except nowait)"},
+};
+
+char Lio_SysCall[PATH_MAX]; /* string containing last i/o system call */
+
+static volatile int Received_signal = 0; /* number of signals received */
+static volatile int Rec_signal;
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+static volatile int Received_callback = 0; /* number of callbacks received */
+static volatile int Rec_callback;
+#endif
+static char Errormsg[500];
+static int Debug_level = 0;
+
+/***********************************************************************
+ * stride_bounds()
+ *
+ * Determine the bounds of a strided request, normalized to offset. Returns
+ * the number of bytes needed to satisfy the request, and optionally sets
+ * *min and *max to the mininum and maximum bytes referenced, normalized
+ * around offset.
+ *
+ * Returns -1 on error - the only possible error conditions are illegal values
+ * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
+ *
+ * (maule, 11/16/95)
+ ***********************************************************************/
+
+int stride_bounds(int offset, int stride, int nstrides, int bytes_per_stride,
+ int *min, int *max)
+{
+ int nbytes, min_byte, max_byte;
+
+ /*
+ * sanity checks ...
+ */
+
+ if (nstrides < 0 || bytes_per_stride < 0) {
+ return -1;
+ }
+
+ if (stride == 0) {
+ stride = bytes_per_stride;
+ }
+
+ /*
+ * Determine the # of bytes needed to satisfy the request. This
+ * value, along with the offset argument, determines the min and max
+ * bytes referenced.
+ */
+
+ nbytes = abs(stride) * (nstrides - 1) + bytes_per_stride;
+
+ if (stride < 0) {
+ max_byte = offset + bytes_per_stride - 1;
+ min_byte = max_byte - nbytes + 1;
+ } else {
+ min_byte = offset;
+ max_byte = min_byte + nbytes - 1;
+ }
+
+ if (min != NULL) {
+ *min = min_byte;
+ }
+
+ if (max != NULL) {
+ *max = max_byte;
+ }
+
+ return nbytes;
+}
+
+/***********************************************************************
+ * This function will allow someone to set the debug level.
+ ***********************************************************************/
+int lio_set_debug(int level)
+{
+ int old;
+
+ old = Debug_level;
+ Debug_level = level;
+ return old;
+}
+
+/***********************************************************************
+ * This function will parse a string and return desired io-method.
+ * Only the first character of the string is used.
+ *
+ * This function does not provide for meaningful option arguments,
+ * but it supports current growfiles/btlk interface.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int lio_parse_io_arg1(char *string)
+{
+ unsigned int ind;
+ int found = 0;
+ int mask = 0;
+
+ /*
+ * Determine if token is a valid string.
+ */
+ for (ind = 0; ind < sizeof(Lio_info1) / sizeof(struct lio_info_type);
+ ind++) {
+ if (strcmp(string, Lio_info1[ind].token) == 0) {
+ mask |= Lio_info1[ind].bits;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ return -1;
+ }
+
+ return mask;
+
+}
+
+/***********************************************************************
+ * This function will print a help message describing the characters
+ * that can be parsed by lio_parse_io_arg1().
+ * They will be printed one per line.
+ * (rrl 04/96)
+ ***********************************************************************/
+void lio_help1(char *prefix)
+{
+ unsigned int ind;
+
+ for (ind = 0; ind < sizeof(Lio_info1) / sizeof(struct lio_info_type);
+ ind++) {
+ printf("%s %s : %s\n", prefix, Lio_info1[ind].token,
+ Lio_info1[ind].desc);
+ }
+
+ return;
+}
+
+/***********************************************************************
+ * This function will parse a string and return the desired io-method.
+ * This function will take a comma separated list of io type and wait
+ * method tokens as defined in Lio_info2[]. If a token does not match
+ * any of the tokens in Lio_info2[], it will be coverted to a number.
+ * If it was a number, those bits are also set.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int lio_parse_io_arg2(char *string, char **badtoken)
+{
+ char *token = string;
+ char *cc = token;
+ char savecc;
+ int found;
+ int mask = 0;
+
+ int tmp;
+ unsigned int ind;
+ char chr;
+
+ if (token == NULL)
+ return -1;
+
+ for (;;) {
+ for (; ((*cc != ',') && (*cc != '\0')); cc++) ;
+ savecc = *cc;
+ *cc = '\0';
+
+ found = 0;
+
+ /*
+ * Determine if token is a valid string or number and if
+ * so, add the bits to the mask.
+ */
+ for (ind = 0;
+ ind < sizeof(Lio_info2) / sizeof(struct lio_info_type);
+ ind++) {
+ if (strcmp(token, Lio_info2[ind].token) == 0) {
+ mask |= Lio_info2[ind].bits;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If token does not match one of the defined tokens, determine
+ * if it is a number, if so, add the bits.
+ */
+ if (!found) {
+ if (sscanf(token, "%i%c", &tmp, &chr) == 1) {
+ mask |= tmp;
+ found = 1;
+ }
+ }
+
+ *cc = savecc;
+
+ if (!found) { /* token is not valid */
+ if (badtoken != NULL)
+ *badtoken = token;
+ return (-1);
+ }
+
+ if (savecc == '\0')
+ break;
+
+ token = ++cc;
+ }
+
+ return mask;
+}
+
+/***********************************************************************
+ * This function will print a help message describing the tokens
+ * that can be parsed by lio_parse_io_arg2().
+ * It will print them one per line.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+void lio_help2(char *prefix)
+{
+ unsigned int ind;
+
+ for (ind = 0; ind < sizeof(Lio_info2) / sizeof(struct lio_info_type);
+ ind++) {
+ printf("%s %s : %s\n", prefix, Lio_info2[ind].token,
+ Lio_info2[ind].desc);
+ }
+ return;
+}
+
+/***********************************************************************
+ * This is an internal signal handler.
+ * If the handler is called, it will increment the Received_signal
+ * global variable.
+ ***********************************************************************/
+static void lio_async_signal_handler(int sig)
+{
+ if (Debug_level)
+ printf
+ ("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
+ __FILE__, __LINE__, sig, Received_signal + 1);
+
+ Received_signal++;
+
+ return;
+}
+
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+/***********************************************************************
+ * This is an internal callback handler.
+ * If the handler is called, it will increment the Received_callback
+ * global variable.
+ ***********************************************************************/
+static void lio_async_callback_handler(union sigval sigval)
+{
+ if (Debug_level)
+ printf
+ ("DEBUG %s/%d: received callback, nbytes=%ld, a callback called %d times\n",
+ __FILE__, __LINE__, (long)sigval.sival_int,
+ Received_callback + 1);
+
+ Received_callback++;
+
+ return;
+}
+#endif /* sgi */
+
+/***********************************************************************
+ * lio_random_methods
+ * This function will randomly choose an io type and wait method
+ * from set of io types and wait methods. Since this information
+ * is stored in a bitmask, it randomly chooses an io type from
+ * the io type bits specified and does the same for wait methods.
+ *
+ * Return Value
+ * This function will return a value with all non choosen io type
+ * and wait method bits cleared. The LIO_RANDOM bit is also
+ * cleared. All other bits are left unchanged.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int lio_random_methods(long curr_mask)
+{
+ int mask = 0;
+
+ /* remove random select, io type, and wait method bits from curr_mask */
+ mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
+
+ /* randomly select io type from specified io types */
+ mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
+
+ /* randomly select wait methods from specified wait methods */
+ mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
+
+ return mask;
+}
+
+static void wait4sync_io(int fd, int read)
+{
+ fd_set s;
+ FD_ZERO(&s);
+ FD_SET(fd, &s);
+
+ select(fd + 1, read ? &s : NULL, read ? NULL : &s, NULL, NULL);
+}
+
+/***********************************************************************
+ * Generic write function
+ * This function can be used to do a write using write(2), writea(2),
+ * aio_write(3), writev(2), pwrite(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of write and the wait method
+ * that will be used. If no io type bits are set, write will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
+ * aio_write(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified,
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set. This will reset an already
+ * set handler for this signal.
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer. If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ * If a system call fails, -errno is returned.
+ * If LIO_WAIT_NONE bit is set, the return value is the return value
+ * of the system call.
+ * If the io did not fail, the amount of data written is returned.
+ * If the size the system call say was written is different
+ * then what was asked to be written, errmsg is updated for
+ * this error condition. The return value is still the amount
+ * the system call says was written.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int lio_write_buffer(int fd, /* open file descriptor */
+ int method, /* contains io type and wait method bitmask */
+ char *buffer, /* pointer to buffer */
+ int size, /* the size of the io */
+ int sig, /* signal to use if async io */
+ char **errmsg, /* char pointer that will be updated to point to err message */
+ long wrd) /* to allow future features, use zero for now */
+{
+ int ret = 0; /* syscall return or used to get random method */
+ char *io_type; /* Holds string of type of io */
+ int omethod = method;
+ int listio_cmd; /* Holds the listio/lio_listio cmd */
+#ifdef CRAY
+ struct listreq request; /* Used when a listio is wanted */
+ struct iosw status, *statptr[1];
+#else
+ /* for linux or sgi */
+ struct iovec iov; /* iovec for writev(2) */
+#endif
+#if defined (sgi)
+ aiocb_t aiocbp; /* POSIX aio control block */
+ aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pwrite(2) offset */
+#endif
+#if defined(__linux__) && !defined(__UCLIBC__)
+ struct aiocb aiocbp; /* POSIX aio control block */
+ struct aiocb *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pwrite(2) offset */
+#endif
+ /*
+ * If LIO_RANDOM bit specified, get new method randomly.
+ */
+ if (method & LIO_RANDOM) {
+ if (Debug_level > 3)
+ printf("DEBUG %s/%d: method mask to choose from: %#o\n",
+ __FILE__, __LINE__, method);
+ method = lio_random_methods(method);
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: random chosen method %#o\n",
+ __FILE__, __LINE__, method);
+ }
+
+ if (errmsg != NULL)
+ *errmsg = Errormsg;
+
+ Rec_signal = Received_signal; /* get the current number of signals received */
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ Rec_callback = Received_callback; /* get the current number of callbacks received */
+#endif
+
+#ifdef CRAY
+ memset(&status, 0x00, sizeof(struct iosw));
+ memset(&request, 0x00, sizeof(struct listreq));
+ statptr[0] = &status;
+#else
+ /* for linux or sgi */
+ memset(&iov, 0x00, sizeof(struct iovec));
+ iov.iov_base = buffer;
+ iov.iov_len = size;
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+#if defined(sgi)
+ memset(&aiocbp, 0x00, sizeof(aiocb_t));
+#else
+ memset(&aiocbp, 0x00, sizeof(struct aiocb));
+#endif
+ aiocbp.aio_fildes = fd;
+ aiocbp.aio_nbytes = size;
+ aiocbp.aio_buf = buffer;
+/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+ aiocbp.aio_sigevent.sigev_signo = 0;
+#ifdef sgi
+ aiocbp.aio_sigevent.sigev_func = NULL;
+ aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+#elif defined(__linux__) && !defined(__UCLIBC__)
+ aiocbp.aio_sigevent.sigev_notify_function = NULL;
+ aiocbp.aio_sigevent.sigev_notify_attributes = 0;
+#endif
+ aiolist[0] = &aiocbp;
+
+ if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) {
+ ret = 0;
+ /* If there is an error and it is not ESPIPE then kick out the error.
+ * If the fd is a fifo then we have to make sure that
+ * lio_random_methods() didn't select pwrite/pread; if it did then
+ * switch to write/read.
+ */
+ if (errno == ESPIPE) {
+ if (method & LIO_IO_SYNCP) {
+ if (omethod & LIO_RANDOM) {
+ method &= ~LIO_IO_SYNCP;
+ method |= LIO_IO_SYNC;
+ if (Debug_level > 2)
+ printf
+ ("DEBUG %s/%d: random chosen method switched to %#o for fifo\n",
+ __FILE__, __LINE__,
+ method);
+ } else if (Debug_level) {
+ printf
+ ("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n",
+ __FILE__, __LINE__);
+ }
+ }
+ /* else: let it ride */
+ } else {
+ sprintf(Errormsg,
+ "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+ }
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ poffset = (off64_t) ret;
+#endif
+ aiocbp.aio_offset = ret;
+
+#endif
+
+ /*
+ * If the LIO_USE_SIGNAL bit is not set, only use the signal
+ * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
+ * Otherwise there is not necessary a signal handler to trap
+ * the signal.
+ */
+ if (sig && !(method & LIO_USE_SIGNAL) && !(method & LIO_WAIT_SIGTYPES)) {
+
+ sig = 0; /* ignore signal parameter */
+ }
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ if (sig && (method & LIO_WAIT_CBTYPES))
+ sig = 0; /* ignore signal parameter */
+#endif
+
+ /*
+ * only setup signal hander if sig was specified and
+ * a sig wait method was specified.
+ * Doing this will change the handler for this signal. The
+ * old signal handler will not be restored.
+ *** restoring the signal handler could be added ***
+ */
+
+ if (sig && (method & LIO_WAIT_SIGTYPES)) {
+#ifdef CRAY
+ sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocbp.aio_sigevent.sigev_signo = sig;
+ sigset(sig, lio_async_signal_handler);
+#endif /* sgi */
+ }
+#if defined(sgi)
+ else if (method & LIO_WAIT_CBTYPES) {
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+ aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+ aiocbp.aio_sigevent.sigev_value.sival_int = size;
+ }
+#endif
+#if defined(__linux__) && !defined(__UCLIBC__)
+ else if (method & LIO_WAIT_CBTYPES) {
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD;
+ aiocbp.aio_sigevent.sigev_notify_function =
+ lio_async_callback_handler;
+ aiocbp.aio_sigevent.sigev_notify_attributes =
+ (void *)(uintptr_t) size;
+ }
+#endif
+ /*
+ * Determine the system call that will be called and produce
+ * the string of the system call and place it in Lio_SysCall.
+ * Also update the io_type char pointer to give brief description
+ * of system call. Execute the system call and check for
+ * system call failure. If sync i/o, return the number of
+ * bytes written/read.
+ */
+
+ if ((method & LIO_IO_SYNC)
+ || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) {
+ /*
+ * write(2) is used if LIO_IO_SYNC bit is set or not none
+ * of the LIO_IO_TYPES bits are set (default).
+ */
+
+ sprintf(Lio_SysCall, "write(%d, buf, %d)", fd, size);
+ io_type = "write";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+ while (1) {
+ if (((ret = write(fd, buffer, size)) == -1)
+ && errno != EAGAIN && errno != EINTR) {
+ sprintf(Errormsg,
+ "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size, errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ if (ret != -1) {
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d write(%d, buf, %d) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ size -= ret;
+ buffer += ret;
+ } else {
+ if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: write completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ }
+ }
+ wait4sync_io(fd, 0);
+ }
+
+ }
+
+ else if (method & LIO_IO_ASYNC) {
+#ifdef CRAY
+ sprintf(Lio_SysCall,
+ "writea(%d, buf, %d, &status, %d)", fd, size, sig);
+ io_type = "writea";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if ((ret = writea(fd, buffer, size, &status, sig)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ sprintf(Lio_SysCall,
+ "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd,
+ size, sig);
+ io_type = "aio_write";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if ((ret = aio_write(&aiocbp)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+#endif
+ }
+ /* LIO_IO_ASYNC */
+ else if (method & LIO_IO_SLISTIO) {
+#ifdef CRAY
+ request.li_opcode = LO_WRITE;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd = LC_WAIT;
+ io_type = "listio(2) sync write";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if (listio(listio_cmd, &request, 1) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+
+ if (Debug_level > 1)
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret = lio_check_asyncio(io_type, size, &status);
+ return ret;
+
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+
+ aiocbp.aio_lio_opcode = LIO_WRITE;
+ listio_cmd = LIO_WAIT;
+ io_type = "lio_listio(3) sync write";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d",
+ fd, size, sig);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+
+ if (Debug_level > 1)
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret = lio_check_asyncio(io_type, size, &aiocbp, method);
+ return ret;
+#endif
+ }
+ /* LIO_IO_SLISTIO */
+ else if (method & LIO_IO_ALISTIO) {
+#ifdef CRAY
+ request.li_opcode = LO_WRITE;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd = LC_START;
+ io_type = "listio(2) async write";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if (listio(listio_cmd, &request, 1) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#if defined (sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ aiocbp.aio_lio_opcode = LIO_WRITE;
+ listio_cmd = LIO_NOWAIT;
+ io_type = "lio_listio(3) async write";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+#endif
+ }
+ /* LIO_IO_ALISTIO */
+#ifndef CRAY
+ else if (method & LIO_IO_SYNCV) {
+ io_type = "writev(2)";
+
+ sprintf(Lio_SysCall, "writev(%d, &iov, 1) nbyte:%d", fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+ if ((ret = writev(fd, &iov, 1)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size, errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
+ __FILE__, __LINE__, fd, size, ret);
+ } else if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: writev completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCV */
+#endif
+
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ else if (method & LIO_IO_SYNCP) {
+ io_type = "pwrite(2)";
+
+ sprintf(Lio_SysCall,
+ "pwrite(%d, buf, %d, %lld)", fd, size,
+ (long long)poffset);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+ if ((ret = pwrite(fd, buffer, size, poffset)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size,
+ (long long)poffset, errno, strerror(errno));
+ return -errno;
+ }
+
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d pwrite(%d, buf, %d, %lld) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, (long long)poffset, ret);
+ } else if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: pwrite completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCP */
+#endif
+
+ else {
+ printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__,
+ __LINE__);
+ return -1;
+ }
+
+ /*
+ * wait for async io to complete.
+ */
+#ifdef CRAY
+ ret = lio_wait4asyncio(method, fd, statptr);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ ret = lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+ /*
+ * If there was an error waiting for async i/o to complete,
+ * return the error value (errno) to the caller.
+ * Note: Errormsg should already have been updated.
+ */
+ if (ret < 0) {
+ return ret;
+ }
+
+ /*
+ * If i/o was not waited for (may not have been completed at this time),
+ * return the size that was requested.
+ */
+ if (ret == 1)
+ return size;
+
+ /*
+ * check that async io was successful.
+ * Note: if the there was an system call failure, -errno
+ * was returned and Errormsg should already have been updated.
+ * If amount i/o was different than size, Errormsg should already
+ * have been updated but the actual i/o size if returned.
+ */
+
+#ifdef CRAY
+ ret = lio_check_asyncio(io_type, size, &status);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ ret = lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+ return ret;
+} /* end of lio_write_buffer */
+
+/***********************************************************************
+ * Generic read function
+ * This function can be used to do a read using read(2), reada(2),
+ * aio_read(3), readv(2), pread(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of read and the wait method
+ * that will be used. If no io type bits are set, read will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
+ * aio_read(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified,
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set. This will reset an already
+ * set handler for this signal.
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer. If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ * If a system call fails, -errno is returned.
+ * If LIO_WAIT_NONE bit is set, the return value is the return value
+ * of the system call.
+ * If the io did not fail, the amount of data written is returned.
+ * If the size the system call say was written is different
+ * then what was asked to be written, errmsg is updated for
+ * this error condition. The return value is still the amount
+ * the system call says was written.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int lio_read_buffer(int fd, /* open file descriptor */
+ int method, /* contains io type and wait method bitmask*/
+ char *buffer, /* pointer to buffer */
+ int size, /* the size of the io */
+ int sig, /* signal to use if async io */
+ char **errmsg, /* char pointer that will be updated to point to err message */
+ long wrd) /* to allow future features, use zero for now */
+{
+ int ret = 0; /* syscall return or used to get random method */
+ char *io_type; /* Holds string of type of io */
+ int listio_cmd; /* Holds the listio/lio_listio cmd */
+ int omethod = method;
+#ifdef CRAY
+ struct listreq request; /* Used when a listio is wanted */
+ struct iosw status, *statptr[1];
+#else
+ /* for linux or sgi */
+ struct iovec iov; /* iovec for readv(2) */
+#endif
+#ifdef sgi
+ aiocb_t aiocbp; /* POSIX aio control block */
+ aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pread(2) offset */
+#endif
+#if defined (__linux__) && !defined(__UCLIBC__)
+ struct aiocb aiocbp; /* POSIX aio control block */
+ struct aiocb *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pread(2) offset */
+#endif
+
+ /*
+ * If LIO_RANDOM bit specified, get new method randomly.
+ */
+ if (method & LIO_RANDOM) {
+ if (Debug_level > 3)
+ printf("DEBUG %s/%d: method mask to choose from: %#o\n",
+ __FILE__, __LINE__, method);
+ method = lio_random_methods(method);
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: random chosen method %#o\n",
+ __FILE__, __LINE__, method);
+ }
+
+ if (errmsg != NULL)
+ *errmsg = Errormsg;
+
+ Rec_signal = Received_signal; /* get the current number of signals received */
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ Rec_callback = Received_callback; /* get the current number of callbacks received */
+#endif
+
+#ifdef CRAY
+ memset(&status, 0x00, sizeof(struct iosw));
+ memset(&request, 0x00, sizeof(struct listreq));
+ statptr[0] = &status;
+#else
+ /* for linux or sgi */
+ memset(&iov, 0x00, sizeof(struct iovec));
+ iov.iov_base = buffer;
+ iov.iov_len = size;
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+#if defined(sgi)
+ memset(&aiocbp, 0x00, sizeof(aiocb_t));
+#else
+ memset(&aiocbp, 0x00, sizeof(struct aiocb));
+#endif
+ aiocbp.aio_fildes = fd;
+ aiocbp.aio_nbytes = size;
+ aiocbp.aio_buf = buffer;
+/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+ aiocbp.aio_sigevent.sigev_signo = 0;
+#ifdef sgi
+ aiocbp.aio_sigevent.sigev_func = NULL;
+ aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+#elif defined(__linux__) && !defined(__UCLIBC__)
+ aiocbp.aio_sigevent.sigev_notify_function = NULL;
+ aiocbp.aio_sigevent.sigev_notify_attributes = 0;
+#endif
+ aiolist[0] = &aiocbp;
+
+ if ((ret = lseek(fd, 0, SEEK_CUR)) == -1) {
+ ret = 0;
+ /* If there is an error and it is not ESPIPE then kick out the error.
+ * If the fd is a fifo then we have to make sure that
+ * lio_random_methods() didn't select pwrite/pread; if it did then
+ * switch to write/read.
+ */
+ if (errno == ESPIPE) {
+ if (method & LIO_IO_SYNCP) {
+ if (omethod & LIO_RANDOM) {
+ method &= ~LIO_IO_SYNCP;
+ method |= LIO_IO_SYNC;
+ if (Debug_level > 2)
+ printf
+ ("DEBUG %s/%d: random chosen method switched to %#o for fifo\n",
+ __FILE__, __LINE__,
+ method);
+ } else if (Debug_level) {
+ printf
+ ("DEBUG %s/%d: pread will fail when it reads from a fifo\n",
+ __FILE__, __LINE__);
+ }
+ }
+ /* else: let it ride */
+ } else {
+ sprintf(Errormsg,
+ "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+ }
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ poffset = (off64_t) ret;
+#endif
+ aiocbp.aio_offset = ret;
+
+#endif
+
+ /*
+ * If the LIO_USE_SIGNAL bit is not set, only use the signal
+ * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
+ * Otherwise there is not necessarily a signal handler to trap
+ * the signal.
+ */
+ if (sig && !(method & LIO_USE_SIGNAL) && !(method & LIO_WAIT_SIGTYPES)) {
+
+ sig = 0; /* ignore signal parameter */
+ }
+#if defined(sgi) || (defined(__linux__)&& !defined(__UCLIBC__))
+ if (sig && (method & LIO_WAIT_CBTYPES))
+ sig = 0; /* ignore signal parameter */
+#endif
+
+ /*
+ * only setup signal hander if sig was specified and
+ * a sig wait method was specified.
+ * Doing this will change the handler for this signal. The
+ * old signal handler will not be restored.
+ *** restoring the signal handler could be added ***
+ */
+
+ if (sig && (method & LIO_WAIT_SIGTYPES)) {
+#ifdef CRAY
+ sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocbp.aio_sigevent.sigev_signo = sig;
+ sigset(sig, lio_async_signal_handler);
+#endif /* CRAY */
+ }
+#if defined(sgi)
+ else if (method & LIO_WAIT_CBTYPES) {
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+ aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_value.sival_int = size;
+ }
+#endif
+#if defined(__linux__) && !defined(__UCLIBC__)
+ else if (method & LIO_WAIT_CBTYPES) {
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_THREAD;
+ aiocbp.aio_sigevent.sigev_notify_function =
+ lio_async_callback_handler;
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_notify_attributes =
+ (void *)(uintptr_t) size;
+ }
+#endif
+
+ /*
+ * Determine the system call that will be called and produce
+ * the string of the system call and place it in Lio_SysCall.
+ * Also update the io_type char pointer to give brief description
+ * of system call. Execute the system call and check for
+ * system call failure. If sync i/o, return the number of
+ * bytes written/read.
+ */
+
+ if ((method & LIO_IO_SYNC)
+ || (method & (LIO_IO_TYPES | LIO_IO_ATYPES)) == 0) {
+ /*
+ * read(2) is used if LIO_IO_SYNC bit is set or not none
+ * of the LIO_IO_TYPES bits are set (default).
+ */
+
+ sprintf(Lio_SysCall, "read(%d, buf, %d)", fd, size);
+ io_type = "read";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ while (1) {
+ if (((ret = read(fd, buffer, size)) == -1)
+ && errno != EINTR && errno != EAGAIN) {
+ sprintf(Errormsg,
+ "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size, errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ if (ret == 0)
+ return 0;
+ if (ret != -1) {
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d read(%d, buf, %d) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ size -= ret;
+ buffer += ret;
+ } else {
+ if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: read completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ }
+ }
+ wait4sync_io(fd, 1);
+ }
+
+ }
+
+ else if (method & LIO_IO_ASYNC) {
+#ifdef CRAY
+ sprintf(Lio_SysCall,
+ "reada(%d, buf, %d, &status, %d)", fd, size, sig);
+ io_type = "reada";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if ((ret = reada(fd, buffer, size, &status, sig)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ sprintf(Lio_SysCall,
+ "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd,
+ size, sig);
+ io_type = "aio_read";
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if ((ret = aio_read(&aiocbp)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+#endif
+ }
+ /* LIO_IO_ASYNC */
+ else if (method & LIO_IO_SLISTIO) {
+#ifdef CRAY
+ request.li_opcode = LO_READ;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd = LC_WAIT;
+ io_type = "listio(2) sync read";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if (listio(listio_cmd, &request, 1) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+
+ if (Debug_level > 1)
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret = lio_check_asyncio(io_type, size, &status);
+ return ret;
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ aiocbp.aio_lio_opcode = LIO_READ;
+ listio_cmd = LIO_WAIT;
+ io_type = "lio_listio(3) sync read";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+
+ if (Debug_level > 1)
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret = lio_check_asyncio(io_type, size, &aiocbp, method);
+ return ret;
+#endif
+ }
+ /* LIO_IO_SLISTIO */
+ else if (method & LIO_IO_ALISTIO) {
+#ifdef CRAY
+ request.li_opcode = LO_READ;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd = LC_START;
+ io_type = "listio(2) async read";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ sigoff();
+ if (listio(listio_cmd, &request, 1) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ aiocbp.aio_lio_opcode = LIO_READ;
+ listio_cmd = LIO_NOWAIT;
+ io_type = "lio_listio(3) async read";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+
+ if (sig)
+ sighold(sig);
+ if (lio_listio(listio_cmd, aiolist, 1, NULL) == -1) {
+ sprintf(Errormsg,
+ "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__, Lio_SysCall, fd, size,
+ errno, strerror(errno));
+ if (sig)
+ sigrelse(sig);
+ return -errno;
+ }
+#endif
+ }
+ /* LIO_IO_ALISTIO */
+#ifndef CRAY
+ else if (method & LIO_IO_SYNCV) {
+ io_type = "readv(2)";
+
+ sprintf(Lio_SysCall, "readv(%d, &iov, 1) nbyte:%d", fd, size);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+ if ((ret = readv(fd, &iov, 1)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size, errno,
+ strerror(errno));
+ return -errno;
+ }
+
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
+ __FILE__, __LINE__, fd, size, ret);
+ } else if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: readv completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCV */
+#endif
+
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ else if (method & LIO_IO_SYNCP) {
+ io_type = "pread(2)";
+
+ sprintf(Lio_SysCall,
+ "pread(%d, buf, %d, %lld)", fd, size,
+ (long long)poffset);
+
+ if (Debug_level) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__,
+ Lio_SysCall);
+ }
+ if ((ret = pread(fd, buffer, size, poffset)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+ __FILE__, __LINE__, fd, size,
+ (long long)poffset, errno, strerror(errno));
+ return -errno;
+ }
+
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d pread(%d, buf, %d, %lld) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, (long long)poffset, ret);
+ } else if (Debug_level > 1)
+ printf
+ ("DEBUG %s/%d: pread completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCP */
+#endif
+
+ else {
+ printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__,
+ __LINE__);
+ return -1;
+ }
+
+ /*
+ * wait for async io to complete.
+ * Note: Sync io should have returned prior to getting here.
+ */
+#ifdef CRAY
+ ret = lio_wait4asyncio(method, fd, statptr);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ ret = lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+ /*
+ * If there was an error waiting for async i/o to complete,
+ * return the error value (errno) to the caller.
+ * Note: Errormsg should already have been updated.
+ */
+ if (ret < 0) {
+ return ret;
+ }
+
+ /*
+ * If i/o was not waited for (may not have been completed at this time),
+ * return the size that was requested.
+ */
+ if (ret == 1)
+ return size;
+
+ /*
+ * check that async io was successful.
+ * Note: if the there was an system call failure, -errno
+ * was returned and Errormsg should already have been updated.
+ * If amount i/o was different than size, Errormsg should already
+ * have been updated but the actual i/o size if returned.
+ */
+
+#ifdef CRAY
+ ret = lio_check_asyncio(io_type, size, &status);
+#endif
+#if defined(sgi) || (defined(__linux__) && !defined(__UCLIBC__))
+ ret = lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+ return ret;
+} /* end of lio_read_buffer */
+
+#if !defined(__sun) && !defined(__hpux) && !defined(_AIX)
+/***********************************************************************
+ * This function will check that async io was successful.
+ * It can also be used to check sync listio since it uses the
+ * same method.
+ *
+ * Return Values
+ * If status.sw_error is set, -status.sw_error is returned.
+ * Otherwise sw_count's field value is returned.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+#ifdef CRAY
+int lio_check_asyncio(char *io_type, int size, struct iosw *status)
+#elif defined(sgi)
+int lio_check_asyncio(char *io_type, int size, aiocb_t * aiocbp, int method)
+#elif defined(__linux__) && !defined(__UCLIBC__)
+int lio_check_asyncio(char *io_type, int size, struct aiocb *aiocbp, int method)
+{
+ int ret;
+
+#ifdef CRAY
+ if (status->sw_error) {
+ sprintf(Errormsg,
+ "%s/%d %s, sw_error set = %d %s, sw_count = %d",
+ __FILE__, __LINE__, io_type,
+ status->sw_error, strerror(status->sw_error),
+ status->sw_count);
+ return -status->sw_error;
+ } else if (status->sw_count != size) {
+ sprintf(Errormsg,
+ "%s/%d %s, sw_count not as expected(%d), but actual:%d",
+ __FILE__, __LINE__, io_type, size, status->sw_count);
+ } else if (Debug_level > 1) {
+ printf
+ ("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n",
+ __FILE__, __LINE__, io_type, status->sw_count);
+ }
+
+ return status->sw_count;
+
+#else
+
+ int cnt = 1;
+
+ /* The I/O may have been synchronous with signal completion. It doesn't
+ * make sense, but the combination could be generated. Release the
+ * completion signal here otherwise it'll hang around and bite us
+ * later.
+ */
+ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL)
+ sigrelse(aiocbp->aio_sigevent.sigev_signo);
+
+ ret = aio_error(aiocbp);
+
+ while (ret == EINPROGRESS) {
+ ret = aio_error(aiocbp);
+ ++cnt;
+ }
+ if (cnt > 1) {
+ sprintf(Errormsg,
+ "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
+ __FILE__, __LINE__, io_type, cnt, method,
+ (aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent.
+ sigev_notify == SIGEV_NONE ? "none" :
+#ifdef SIGEV_CALLBACK
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_CALLBACK ? "callback" :
+#endif
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_THREAD ? "thread" : "unknown"));
+ return -ret;
+ }
+
+ if (ret != 0) {
+ sprintf(Errormsg,
+ "%s/%d %s, aio_error = %d %s; random method %#o",
+ __FILE__, __LINE__, io_type,
+ ret, strerror(ret), method);
+ return -ret;
+ }
+ ret = aio_return(aiocbp);
+ if (ret != size) {
+ sprintf(Errormsg,
+ "%s/%d %s, aio_return not as expected(%d), but actual:%d",
+ __FILE__, __LINE__, io_type, size, ret);
+
+#ifdef BUG1_workaround
+ if (ret == 0) {
+ ret = size;
+ if (Debug_level > 1) {
+ printf
+ ("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
+ __FILE__, __LINE__, io_type, ret);
+ }
+ }
+#endif /* BUG1_workaround */
+
+ } else if (Debug_level > 1) {
+ printf
+ ("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
+ __FILE__, __LINE__, io_type, ret);
+ }
+
+ return ret;
+
+#endif
+} /* end of lio_check_asyncio */
+#endif
+
+/***********************************************************************
+ *
+ * This function will wait for async io to complete.
+ * If multiple wait methods are specified, the order is predetermined
+ * to LIO_WAIT_RECALL,
+ * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
+ * then LIO_WAIT_NONE.
+ *
+ * If no wait method was specified the default wait method is: recall(2)
+ * or aio_suspend(3), as appropriate.
+ *
+ * Return Values
+ * <0: errno of failed recall
+ * 0 : async io was completed
+ * 1 : async was not waited for, io may not have completed.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+#ifdef CRAY
+int lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+#elif defined(sgi)
+int lio_wait4asyncio(int method, int fd, aiocb_t * aiocbp)
+#elif defined(__linux__) && !defined(__UCLIBC__)
+int lio_wait4asyncio(int method, int fd, struct aiocb *aiocbp)
+{
+ int cnt;
+#ifdef sgi
+ int ret;
+ const aiocb_t *aioary[1];
+#endif
+#if defined(__linux__)&& !defined(__UCLIBC__)
+ int ret;
+ const struct aiocb *aioary[1];
+#endif
+
+ if ((method & LIO_WAIT_RECALL)
+#if defined(sgi) || (defined(__linux__)&& !defined(__UCLIBC__))
+ || (method & LIO_WAIT_CBSUSPEND)
+ || (method & LIO_WAIT_SIGSUSPEND)
+#endif
+ || ((method & LIO_WAIT_TYPES) == 0)) {
+ /*
+ * If method has LIO_WAIT_RECALL bit set or method does
+ * not have any wait method bits set (default), use recall/aio_suspend.
+ */
+#ifdef CRAY
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: wait method : recall\n", __FILE__,
+ __LINE__);
+ sigon();
+ if (recall(fd, 1, statptr)) {
+ sprintf(Errormsg,
+ "%s/%d recall(%d, 1, stat) failed, errno:%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+#else
+ if (Debug_level > 2)
+ printf
+ ("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n",
+ __FILE__, __LINE__,
+ (aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_SIGNAL ? "signal" : aiocbp->aio_sigevent.
+ sigev_notify == SIGEV_NONE ? "none" :
+#ifdef SIGEV_CALLBACK
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_CALLBACK ? "callback" :
+#endif
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_THREAD ? "thread" : "unknown"));
+
+ aioary[0] = aiocbp;
+ ret = aio_suspend(aioary, 1, NULL);
+ if ((ret == -1) && (errno == EINTR)) {
+ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) {
+ if (Debug_level > 2) {
+ printf
+ ("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
+ __FILE__, __LINE__);
+ }
+ } else {
+ sprintf(Errormsg,
+ "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
+ __FILE__, __LINE__,
+ (aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_SIGNAL ? "signal" : aiocbp->
+ aio_sigevent.sigev_notify ==
+ SIGEV_NONE ? "none" :
+#ifdef SIGEV_CALLBACK
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_CALLBACK ? "callback" :
+#endif
+ aiocbp->aio_sigevent.sigev_notify ==
+ SIGEV_THREAD ? "thread" : "unknown"));
+ return -errno;
+ }
+ } else if (ret) {
+ sprintf(Errormsg,
+ "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+#endif
+
+ } else if (method & LIO_WAIT_ACTIVE) {
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: wait method : active\n", __FILE__,
+ __LINE__);
+#ifdef CRAY
+ sigon();
+ /*
+ * loop until sw_flag, sw_count or sw_error field elements
+ * change to non-zero.
+ */
+ cnt = 0;
+ while ((*statptr)->sw_flag == 0 &&
+ (*statptr)->sw_count == 0 && (*statptr)->sw_error == 0) {
+ cnt++;
+ }
+#else
+ /* loop while aio_error() returns EINPROGRESS */
+ cnt = 0;
+ while (1) {
+ ret = aio_error(aiocbp);
+ if (ret != EINPROGRESS) {
+ break;
+ }
+ ++cnt;
+ }
+
+#endif
+ if (Debug_level > 5 && cnt && (cnt % 50) == 0)
+ printf("DEBUG %s/%d: wait active cnt = %d\n",
+ __FILE__, __LINE__, cnt);
+
+ } else if (method & LIO_WAIT_SIGPAUSE) {
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: wait method : sigpause\n",
+ __FILE__, __LINE__);
+#ifdef sgi
+ /* note: don't do the sigon() for CRAY in this case. why? -- roehrich 6/11/97 */
+ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL)
+ sigrelse(aiocbp->aio_sigevent.sigev_signo);
+ else {
+ printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+#endif
+ pause();
+
+ } else if (method & LIO_WAIT_SIGACTIVE) {
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: wait method : sigactive\n",
+ __FILE__, __LINE__);
+#ifdef CRAY
+ sigon();
+#else
+ if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL)
+ sigrelse(aiocbp->aio_sigevent.sigev_signo);
+ else {
+ printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+#endif
+ /* loop waiting for signal */
+ while (Received_signal == Rec_signal) {
+#ifdef CRAY
+ sigon();
+#else
+ sigrelse(aiocbp->aio_sigevent.sigev_signo);
+#endif
+ }
+
+ } else if (method & LIO_WAIT_NONE) {
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: wait method : none\n", __FILE__,
+ __LINE__);
+ /* It's broken because the aiocb/iosw is an automatic variable in
+ * lio_{read,write}_buffer, so when the function returns and the
+ * I/O completes there will be nowhere to write the I/O status.
+ * It doesn't cause a problem on unicos--probably because of some
+ * compiler quirk, or an accident. It causes POSIX async I/O
+ * to core dump some threads. spr/pv 705909. 6/27/97 roehrich
+ */
+ sprintf(Errormsg,
+ "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
+ __FILE__, __LINE__);
+#ifdef CRAY
+ sigon();
+#endif
+/* return 1;*/
+ return -1;
+ } else {
+ if (Debug_level > 2)
+ printf("DEBUG %s/%d: no wait method was chosen\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ return 0;
+
+} /* end of lio_wait4asyncio */
+
+#endif /* ifndef linux */
+#endif
+
+#if UNIT_TEST
+/***********************************************************************
+ * The following code is provided as unit test.
+ * Just define add "-DUNIT_TEST=1" to the cc line.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+struct unit_info_t {
+ int method;
+ int sig;
+ char *str;
+} Unit_info[] = {
+ {
+ LIO_IO_SYNC, 0, "sync io"}, {
+ LIO_IO_SYNCV, 0, "sync readv/writev"}, {
+ LIO_IO_SYNCP, 0, "sync pread/pwrite"}, {
+ LIO_IO_ASYNC, 0, "async io, def wait"}, {
+ LIO_IO_SLISTIO, 0, "sync listio"}, {
+ LIO_IO_ALISTIO, 0, "async listio, def wait"}, {
+ LIO_IO_ASYNC | LIO_WAIT_ACTIVE, 0, "async active"}, {
+ LIO_IO_ASYNC | LIO_WAIT_RECALL, 0, "async recall/suspend"}, {
+ LIO_IO_ASYNC | LIO_WAIT_SIGPAUSE, SIGUSR1, "async sigpause"}, {
+ LIO_IO_ASYNC | LIO_WAIT_SIGACTIVE, SIGUSR1, "async sigactive"}, {
+ LIO_IO_ALISTIO | LIO_WAIT_ACTIVE, 0, "async listio active"}, {
+ LIO_IO_ALISTIO | LIO_WAIT_RECALL, 0, "async listio recall"}, {
+ LIO_IO_ALISTIO | LIO_WAIT_SIGACTIVE, SIGUSR1, "async listio sigactive"},
+ {
+ LIO_IO_ALISTIO | LIO_WAIT_SIGPAUSE, SIGUSR1, "async listio sigpause"},
+ {
+ LIO_IO_ASYNC, SIGUSR2, "async io, def wait, sigusr2"}, {
+LIO_IO_ALISTIO, SIGUSR2, "async listio, def wait, sigusr2"},};
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+
+ int fd;
+ char *err;
+ char buffer[4096];
+ int size = 4096;
+ int ret;
+ int ind;
+ int iter = 3;
+ int method;
+ int exit_status = 0;
+ int c;
+ int i;
+ char *symbols = NULL;
+ int die_on_err = 0;
+
+ while ((c = getopt(argc, argv, "s:di:")) != -1) {
+ switch (c) {
+ case 's':
+ symbols = optarg;
+ break;
+ case 'd':
+ ++die_on_err;
+ break;
+ case 'i':
+ iter = atoi(optarg);
+ break;
+ }
+ }
+
+ if ((fd =
+ open("unit_test_file", O_CREAT | O_RDWR | O_TRUNC, 0777)) == -1) {
+ perror
+ ("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
+ exit(1);
+ }
+
+ Debug_level = 9;
+
+ if (symbols != NULL) {
+ if ((method = lio_parse_io_arg2(symbols, &err)) == -1) {
+ printf
+ ("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
+ symbols, err);
+ if (die_on_err)
+ exit(1);
+ } else
+ printf("lio_parse_io_arg2(%s, &err) returned %#o\n",
+ symbols, method);
+
+ exit_status = 0;
+ for (ind = 0; ind < iter; ind++) {
+ memset(buffer, 'A', 4096);
+ if (lseek(fd, 0, 0) == -1) {
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno);
+ ++exit_status;
+ }
+ if ((ret = lio_write_buffer(fd, method, buffer,
+ size, SIGUSR1, &err,
+ 0)) != size) {
+ printf
+ ("lio_write_buffer returned -1, err = %s\n",
+ err);
+ } else
+ printf("lio_write_buffer returned %d\n", ret);
+
+ memset(buffer, 'B', 4096);
+ if (lseek(fd, 0, 0) == -1) {
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno);
+ ++exit_status;
+ }
+ if ((ret = lio_read_buffer(fd, method, buffer,
+ size, SIGUSR2, &err,
+ 0)) != size) {
+ printf
+ ("lio_read_buffer returned -1, err = %s\n",
+ err);
+ } else
+ printf("lio_read_buffer returned %d\n", ret);
+
+ for (i = 0; i < 4096; ++i) {
+ if (buffer[i] != 'A') {
+ printf(" buffer[%d] = %d\n", i,
+ buffer[i]);
+ ++exit_status;
+ break;
+ }
+ }
+
+ if (exit_status)
+ exit(exit_status);
+
+ }
+
+ unlink("unit_test_file");
+ exit(0);
+ }
+
+ for (ind = 0; ind < sizeof(Unit_info) / sizeof(struct unit_info_t);
+ ind++) {
+
+ printf("\n********* write %s ***************\n",
+ Unit_info[ind].str);
+ if (lseek(fd, 0, 0) == -1) {
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno);
+ ++exit_status;
+ }
+
+ memset(buffer, 'A', 4096);
+ if ((ret = lio_write_buffer(fd, Unit_info[ind].method, buffer,
+ size, Unit_info[ind].sig, &err,
+ 0)) != size) {
+ printf
+ (">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
+ Unit_info[ind].method, size, Unit_info[ind].sig,
+ err);
+ ++exit_status;
+ if (die_on_err)
+ exit(exit_status);
+ } else {
+ printf("lio_write_buffer returned %d\n", ret);
+ }
+
+ printf("\n********* read %s ***************\n",
+ Unit_info[ind].str);
+ if (lseek(fd, 0, 0) == -1) {
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno);
+ ++exit_status;
+ }
+ memset(buffer, 'B', 4096);
+ if ((ret = lio_read_buffer(fd, Unit_info[ind].method, buffer,
+ size, Unit_info[ind].sig, &err,
+ 0)) != size) {
+ printf
+ (">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
+ Unit_info[ind].method, size, Unit_info[ind].sig,
+ err);
+ ++exit_status;
+ if (die_on_err)
+ exit(exit_status);
+ } else {
+ printf("lio_read_buffer returned %d\n", ret);
+ }
+
+ for (i = 0; i < 4096; ++i) {
+ if (buffer[i] != 'A') {
+ printf(" buffer[%d] = %d\n", i, buffer[i]);
+ ++exit_status;
+ if (die_on_err)
+ exit(exit_status);
+ break;
+ }
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+ sleep(1);
+
+ }
+
+ unlink("unit_test_file");
+
+ exit(exit_status);
+}
+#endif
diff --git a/src/kernel/tests/lib/tst_af_alg.c b/src/kernel/tests/lib/tst_af_alg.c
new file mode 100644
index 0000000..d3895a8
--- /dev/null
+++ b/src/kernel/tests/lib/tst_af_alg.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_af_alg.h"
+#include "lapi/socket.h"
+
+int tst_alg_create(void)
+{
+ TEST(socket(AF_ALG, SOCK_SEQPACKET, 0));
+ if (TST_RET >= 0)
+ return TST_RET;
+ if (TST_ERR == EAFNOSUPPORT)
+ tst_brk(TCONF, "kernel doesn't support AF_ALG");
+ tst_brk(TBROK | TTERRNO, "unexpected error creating AF_ALG socket");
+ return -1;
+}
+
+void tst_alg_bind_addr(int algfd, const struct sockaddr_alg *addr)
+{
+ TEST(bind(algfd, (const struct sockaddr *)addr, sizeof(*addr)));
+ if (TST_RET == 0)
+ return;
+ if (TST_ERR == ENOENT) {
+ tst_brk(TCONF, "kernel doesn't support %s algorithm '%s'",
+ addr->salg_type, addr->salg_name);
+ }
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error binding AF_ALG socket to %s algorithm '%s'",
+ addr->salg_type, addr->salg_name);
+}
+
+static void init_sockaddr_alg(struct sockaddr_alg *addr,
+ const char *algtype, const char *algname)
+{
+ memset(addr, 0, sizeof(*addr));
+
+ addr->salg_family = AF_ALG;
+
+ strncpy((char *)addr->salg_type, algtype, sizeof(addr->salg_type));
+ if (addr->salg_type[sizeof(addr->salg_type) - 1] != '\0')
+ tst_brk(TBROK, "algorithm type too long: '%s'", algtype);
+
+ strncpy((char *)addr->salg_name, algname, sizeof(addr->salg_name));
+ if (addr->salg_name[sizeof(addr->salg_name) - 1] != '\0')
+ tst_brk(TBROK, "algorithm name too long: '%s'", algname);
+}
+
+void tst_alg_bind(int algfd, const char *algtype, const char *algname)
+{
+ struct sockaddr_alg addr;
+
+ init_sockaddr_alg(&addr, algtype, algname);
+
+ tst_alg_bind_addr(algfd, &addr);
+}
+
+bool tst_have_alg(const char *algtype, const char *algname)
+{
+ int algfd;
+ struct sockaddr_alg addr;
+ bool have_alg = true;
+
+ algfd = tst_alg_create();
+
+ init_sockaddr_alg(&addr, algtype, algname);
+
+ TEST(bind(algfd, (const struct sockaddr *)&addr, sizeof(addr)));
+ if (TST_RET != 0) {
+ if (TST_ERR != ENOENT) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error binding AF_ALG socket to %s algorithm '%s'",
+ algtype, algname);
+ }
+ have_alg = false;
+ }
+
+ close(algfd);
+ return have_alg;
+}
+
+void tst_require_alg(const char *algtype, const char *algname)
+{
+ int algfd = tst_alg_create();
+
+ tst_alg_bind(algfd, algtype, algname);
+
+ close(algfd);
+}
+
+void tst_alg_setkey(int algfd, const uint8_t *key, unsigned int keylen)
+{
+ uint8_t *keybuf = NULL;
+ unsigned int i;
+
+ if (key == NULL) {
+ /* generate a random key */
+ keybuf = SAFE_MALLOC(keylen);
+ for (i = 0; i < keylen; i++)
+ keybuf[i] = rand();
+ key = keybuf;
+ }
+ TEST(setsockopt(algfd, SOL_ALG, ALG_SET_KEY, key, keylen));
+ if (TST_RET != 0) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error setting key (len=%u)", keylen);
+ }
+ free(keybuf);
+}
+
+int tst_alg_accept(int algfd)
+{
+ TEST(accept(algfd, NULL, NULL));
+ if (TST_RET < 0) {
+ tst_brk(TBROK | TTERRNO,
+ "unexpected error accept()ing AF_ALG request socket");
+ }
+ return TST_RET;
+}
+
+int tst_alg_setup(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen)
+{
+ int algfd = tst_alg_create();
+
+ tst_alg_bind(algfd, algtype, algname);
+
+ if (keylen != 0)
+ tst_alg_setkey(algfd, key, keylen);
+
+ return algfd;
+}
+
+int tst_alg_setup_reqfd(const char *algtype, const char *algname,
+ const uint8_t *key, unsigned int keylen)
+{
+ int algfd = tst_alg_setup(algtype, algname, key, keylen);
+ int reqfd = tst_alg_accept(algfd);
+
+ close(algfd);
+ return reqfd;
+}
+
+void tst_alg_sendmsg(int reqfd, const void *data, size_t datalen,
+ const struct tst_alg_sendmsg_params *params)
+{
+ struct iovec iov = {
+ .iov_base = (void *)data,
+ .iov_len = datalen,
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_flags = params->msg_flags,
+ };
+ size_t controllen;
+ uint8_t *control;
+ struct cmsghdr *cmsg;
+ struct af_alg_iv *alg_iv;
+
+ if (params->encrypt && params->decrypt)
+ tst_brk(TBROK, "Both encrypt and decrypt are specified");
+
+ controllen = 0;
+ if (params->encrypt || params->decrypt)
+ controllen += CMSG_SPACE(sizeof(uint32_t));
+ if (params->ivlen)
+ controllen += CMSG_SPACE(sizeof(struct af_alg_iv) +
+ params->ivlen);
+ if (params->assoclen)
+ controllen += CMSG_SPACE(sizeof(uint32_t));
+
+ control = SAFE_MALLOC(controllen);
+ memset(control, 0, controllen);
+ msg.msg_control = control;
+ msg.msg_controllen = controllen;
+ cmsg = CMSG_FIRSTHDR(&msg);
+
+ if (params->encrypt || params->decrypt) {
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
+ *(uint32_t *)CMSG_DATA(cmsg) =
+ params->encrypt ? ALG_OP_ENCRYPT : ALG_OP_DECRYPT;
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ }
+ if (params->ivlen) {
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_IV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct af_alg_iv) +
+ params->ivlen);
+ alg_iv = (struct af_alg_iv *)CMSG_DATA(cmsg);
+ alg_iv->ivlen = params->ivlen;
+ memcpy(alg_iv->iv, params->iv, params->ivlen);
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ }
+ if (params->assoclen) {
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
+ *(uint32_t *)CMSG_DATA(cmsg) = params->assoclen;
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ }
+
+ SAFE_SENDMSG(datalen, reqfd, &msg, 0);
+}
diff --git a/src/kernel/tests/lib/tst_ansi_color.c b/src/kernel/tests/lib/tst_ansi_color.c
new file mode 100644
index 0000000..1c29268
--- /dev/null
+++ b/src/kernel/tests/lib/tst_ansi_color.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tst_res_flags.h"
+#include "tst_ansi_color.h"
+
+char* tst_ttype2color(int ttype)
+{
+ switch (TTYPE_RESULT(ttype)) {
+ case TPASS:
+ return ANSI_COLOR_GREEN;
+ break;
+ case TFAIL:
+ return ANSI_COLOR_RED;
+ break;
+ case TBROK:
+ return ANSI_COLOR_RED;
+ break;
+ case TCONF:
+ return ANSI_COLOR_YELLOW;
+ break;
+ case TWARN:
+ return ANSI_COLOR_MAGENTA;
+ break;
+ case TINFO:
+ return ANSI_COLOR_BLUE;
+ break;
+ default:
+ return "";
+ }
+}
+
+int tst_color_enabled(int fd)
+{
+ static int color;
+
+ if (color)
+ return color - 1;
+
+ char *env = getenv("LTP_COLORIZE_OUTPUT");
+
+ if (env) {
+ if (!strcmp(env, "n") || !strcmp(env, "0"))
+ color = 1;
+
+ if (!strcmp(env, "y") || !strcmp(env, "1"))
+ color = 2;
+
+ return color - 1;
+ }
+
+ if (isatty(fd) == 0)
+ color = 1;
+ else
+ color = 2;
+
+ return color - 1;
+}
diff --git a/src/kernel/tests/lib/tst_assert.c b/src/kernel/tests/lib/tst_assert.c
new file mode 100644
index 0000000..9b8ebc1
--- /dev/null
+++ b/src/kernel/tests/lib/tst_assert.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
+ * Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz>
+ */
+#include <stdio.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_assert.h"
+#include "tst_test.h"
+
+void tst_assert_int(const char *file, const int lineno, const char *path, int val)
+{
+ int sys_val;
+
+ safe_file_scanf(file, lineno, NULL, path, "%d", &sys_val);
+
+ if (val == sys_val) {
+ tst_res_(file, lineno, TPASS, "%s = %d", path, val);
+ return;
+ }
+
+ tst_res_(file, lineno, TFAIL, "%s != %d got %d", path, val, sys_val);
+}
+
+void tst_assert_ulong(const char *file, const int lineno, const char *path, unsigned long val)
+{
+ unsigned long sys_val;
+
+ safe_file_scanf(file, lineno, NULL, path, "%lu", &sys_val);
+
+ if (val == sys_val) {
+ tst_res_(file, lineno, TPASS, "%s = %lu", path, val);
+ return;
+ }
+
+ tst_res_(file, lineno, TFAIL, "%s != %lu got %lu", path, val, sys_val);
+}
+
+void tst_assert_file_int(const char *file, const int lineno, const char *path, const char *prefix, int val)
+{
+ int sys_val;
+ char fmt[1024];
+
+ snprintf(fmt, sizeof(fmt), "%s%%d", prefix);
+ file_lines_scanf(file, lineno, NULL, 1, path, fmt, &sys_val);
+
+ if (val == sys_val) {
+ tst_res_(file, lineno, TPASS, "%s %s = %d", path, prefix, sys_val);
+ return;
+ }
+
+ tst_res_(file, lineno, TFAIL, "%s %s != %d got %d", path, prefix, val, sys_val);
+}
+
+void tst_assert_str(const char *file, const int lineno, const char *path, const char *val)
+{
+ char sys_val[1024];
+
+ safe_file_scanf(file, lineno, NULL, path, "%1024s", sys_val);
+ if (!strcmp(val, sys_val)) {
+ tst_res_(file, lineno, TPASS, "%s = '%s'", path, val);
+ return;
+ }
+
+ tst_res_(file, lineno, TFAIL, "%s != '%s' got '%s'", path, val, sys_val);
+}
+
+void tst_assert_file_str(const char *file, const int lineno, const char *path, const char *prefix, const char *val)
+{
+ char sys_val[1024];
+ char fmt[2048];
+
+ snprintf(fmt, sizeof(fmt), "%s: %%1024s", prefix);
+ file_lines_scanf(file, lineno, NULL, 1, path, fmt, sys_val);
+
+ if (!strcmp(val, sys_val)) {
+ tst_res_(file, lineno, TPASS, "%s %s = '%s'", path, prefix, sys_val);
+ return;
+ }
+
+ tst_res_(file, lineno, TFAIL, "%s %s != '%s' got '%s'", path, prefix, val, sys_val);
+}
diff --git a/src/kernel/tests/lib/tst_buffers.c b/src/kernel/tests/lib/tst_buffers.c
new file mode 100644
index 0000000..b8b597a
--- /dev/null
+++ b/src/kernel/tests/lib/tst_buffers.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <sys/mman.h>
+#include <stdlib.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+struct map {
+ void *addr;
+ size_t size;
+ size_t buf_shift;
+ struct map *next;
+};
+
+static struct map *maps;
+
+static void setup_canary(struct map *map)
+{
+ size_t i;
+ char *buf = map->addr;
+
+ for (i = 0; i < map->buf_shift/2; i++) {
+ char c = random();
+ buf[map->buf_shift - i - 1] = c;
+ buf[i] = c;
+ }
+}
+
+static void check_canary(struct map *map)
+{
+ size_t i;
+ char *buf = map->addr;
+
+ for (i = 0; i < map->buf_shift/2; i++) {
+ if (buf[map->buf_shift - i - 1] != buf[i]) {
+ tst_res(TWARN,
+ "pid %i: buffer modified address %p[%zi]",
+ getpid(), (char*)map->addr + map->buf_shift, -i-1);
+ }
+ }
+}
+
+void *tst_alloc(size_t size)
+{
+ size_t page_size = getpagesize();
+ unsigned int pages = (size / page_size) + !!(size % page_size) + 1;
+ void *ret;
+ struct map *map = SAFE_MALLOC(sizeof(struct map));
+ static int print_msg = 1;
+
+ if (print_msg) {
+ tst_res(TINFO, "Test is using guarded buffers");
+ print_msg = 0;
+ }
+
+ ret = SAFE_MMAP(NULL, page_size * pages, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+ mprotect(ret + (pages-1) * page_size, page_size, PROT_NONE);
+
+ map->addr = ret;
+ map->size = pages * page_size;
+ map->next = maps;
+ maps = map;
+
+ if (size % page_size)
+ map->buf_shift = page_size - (size % page_size);
+ else
+ map->buf_shift = 0;
+
+ setup_canary(map);
+
+ return ret + map->buf_shift;
+}
+
+static int count_iovec(int *sizes)
+{
+ int ret = 0;
+
+ while (sizes[ret++] != -1);
+
+ return ret - 1;
+}
+
+struct iovec *tst_iovec_alloc(int sizes[])
+{
+ int i, cnt = count_iovec(sizes);
+ struct iovec *iovec;
+
+ if (cnt <= 0)
+ return NULL;
+
+ iovec = tst_alloc(sizeof(struct iovec) * cnt);
+
+ for (i = 0; i < cnt; i++) {
+ if (sizes[i]) {
+ iovec[i].iov_base = tst_alloc(sizes[i]);
+ iovec[i].iov_len = sizes[i];
+ } else {
+ iovec[i].iov_base = NULL;
+ iovec[i].iov_base = 0;
+ }
+ }
+
+ return iovec;
+}
+
+void tst_buffers_alloc(struct tst_buffers bufs[])
+{
+ unsigned int i;
+
+ for (i = 0; bufs[i].ptr; i++) {
+ if (bufs[i].size)
+ *((void**)bufs[i].ptr) = tst_alloc(bufs[i].size);
+ else
+ *((void**)bufs[i].ptr) = tst_iovec_alloc(bufs[i].iov_sizes);
+ }
+}
+
+char *tst_strdup(const char *str)
+{
+ size_t len = strlen(str);
+ char *ret = tst_alloc(len + 1);
+ return strcpy(ret, str);
+}
+
+void tst_free_all(void)
+{
+ struct map *i = maps;
+
+ while (i) {
+ struct map *j = i;
+ check_canary(i);
+ SAFE_MUNMAP(i->addr, i->size);
+ i = i->next;
+ free(j);
+ }
+
+ maps = NULL;
+}
diff --git a/src/kernel/tests/lib/tst_capability.c b/src/kernel/tests/lib/tst_capability.c
new file mode 100644
index 0000000..1fa0e49
--- /dev/null
+++ b/src/kernel/tests/lib/tst_capability.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ */
+
+#include <string.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_capability.h"
+
+#include "lapi/syscalls.h"
+
+int tst_capget(struct tst_cap_user_header *hdr,
+ struct tst_cap_user_data *data)
+{
+ return tst_syscall(__NR_capget, hdr, data);
+}
+
+int tst_capset(struct tst_cap_user_header *hdr,
+ const struct tst_cap_user_data *data)
+{
+ return tst_syscall(__NR_capset, hdr, data);
+}
+
+static void do_cap_drop(uint32_t *set, uint32_t mask, const struct tst_cap *cap)
+{
+ if (*set & mask) {
+ tst_res(TINFO, "Dropping %s(%d)", cap->name, cap->id);
+ *set &= ~mask;
+ }
+}
+
+static void do_cap_req(uint32_t *permitted, uint32_t *effective, uint32_t mask,
+ const struct tst_cap *cap)
+{
+ if (!(*permitted & mask))
+ tst_brk(TCONF, "Need %s(%d)", cap->name, cap->id);
+
+ if (!(*effective & mask)) {
+ tst_res(TINFO, "Permitting %s(%d)", cap->name, cap->id);
+ *effective |= mask;
+ }
+}
+
+void tst_cap_action(struct tst_cap *cap)
+{
+ struct tst_cap_user_header hdr = {
+ .version = 0x20080522,
+ .pid = tst_syscall(__NR_gettid),
+ };
+ struct tst_cap_user_data cur[2] = { {0} };
+ struct tst_cap_user_data new[2] = { {0} };
+ uint32_t act = cap->action;
+ uint32_t *pE = &new[CAP_TO_INDEX(cap->id)].effective;
+ uint32_t *pP = &new[CAP_TO_INDEX(cap->id)].permitted;
+ uint32_t mask = CAP_TO_MASK(cap->id);
+
+ if (tst_capget(&hdr, cur))
+ tst_brk(TBROK | TTERRNO, "tst_capget()");
+
+ memcpy(new, cur, sizeof(new));
+
+ switch (act) {
+ case TST_CAP_DROP:
+ do_cap_drop(pE, mask, cap);
+ break;
+ case TST_CAP_REQ:
+ do_cap_req(pP, pE, mask, cap);
+ break;
+ default:
+ tst_brk(TBROK, "Unrecognised action %d", cap->action);
+ }
+
+ if (!memcmp(cur, new, sizeof(new)))
+ return;
+
+ if (tst_capset(&hdr, new))
+ tst_brk(TBROK | TERRNO, "tst_capset(%s)", cap->name);
+}
+
+void tst_cap_setup(struct tst_cap *caps, unsigned int action_mask)
+{
+ struct tst_cap *cap;
+
+ for (cap = caps; cap->action; cap++) {
+ if (cap->action & action_mask)
+ tst_cap_action(cap);
+ }
+}
diff --git a/src/kernel/tests/lib/tst_cgroup.c b/src/kernel/tests/lib/tst_cgroup.c
new file mode 100644
index 0000000..ba413d8
--- /dev/null
+++ b/src/kernel/tests/lib/tst_cgroup.c
@@ -0,0 +1,452 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ * Copyright (c) 2020 Li Wang <liwang@redhat.com>
+ */
+
+#define TST_NO_DEFAULT_MAIN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "tst_test.h"
+#include "tst_safe_macros.h"
+#include "tst_safe_stdio.h"
+#include "tst_cgroup.h"
+#include "tst_device.h"
+
+static enum tst_cgroup_ver tst_cg_ver;
+static int clone_children;
+
+static int tst_cgroup_check(const char *cgroup)
+{
+ char line[PATH_MAX];
+ FILE *file;
+ int cg_check = 0;
+
+ file = SAFE_FOPEN("/proc/filesystems", "r");
+ while (fgets(line, sizeof(line), file)) {
+ if (strstr(line, cgroup) != NULL) {
+ cg_check = 1;
+ break;
+ }
+ }
+ SAFE_FCLOSE(file);
+
+ return cg_check;
+}
+
+enum tst_cgroup_ver tst_cgroup_version(void)
+{
+ enum tst_cgroup_ver cg_ver;
+
+ if (tst_cgroup_check("cgroup2")) {
+ if (!tst_is_mounted("cgroup2") && tst_is_mounted("cgroup"))
+ cg_ver = TST_CGROUP_V1;
+ else
+ cg_ver = TST_CGROUP_V2;
+
+ goto out;
+ }
+
+ if (tst_cgroup_check("cgroup"))
+ cg_ver = TST_CGROUP_V1;
+
+ if (!cg_ver)
+ tst_brk(TCONF, "Cgroup is not configured");
+
+out:
+ return cg_ver;
+}
+
+static void tst_cgroup1_mount(const char *name, const char *option,
+ const char *mnt_path, const char *new_path)
+{
+ char knob_path[PATH_MAX];
+ if (tst_is_mounted(mnt_path))
+ goto out;
+
+ SAFE_MKDIR(mnt_path, 0777);
+ if (mount(name, mnt_path, "cgroup", 0, option) == -1) {
+ if (errno == ENODEV) {
+ if (rmdir(mnt_path) == -1)
+ tst_res(TWARN | TERRNO, "rmdir %s failed", mnt_path);
+ tst_brk(TCONF,
+ "Cgroup v1 is not configured in kernel");
+ }
+ tst_brk(TBROK | TERRNO, "mount %s", mnt_path);
+ }
+
+ /*
+ * We should assign one or more memory nodes to cpuset.mems and
+ * cpuset.cpus, otherwise, echo $$ > tasks gives “ENOSPC: no space
+ * left on device” when trying to use cpuset.
+ *
+ * Or, setting cgroup.clone_children to 1 can help in automatically
+ * inheriting memory and node setting from parent cgroup when a
+ * child cgroup is created.
+ */
+ if (strcmp(option, "cpuset") == 0) {
+ sprintf(knob_path, "%s/cgroup.clone_children", mnt_path);
+ SAFE_FILE_SCANF(knob_path, "%d", &clone_children);
+ SAFE_FILE_PRINTF(knob_path, "%d", 1);
+ }
+out:
+ SAFE_MKDIR(new_path, 0777);
+
+ tst_res(TINFO, "Cgroup(%s) v1 mount at %s success", option, mnt_path);
+}
+
+static void tst_cgroup2_mount(const char *mnt_path, const char *new_path)
+{
+ if (tst_is_mounted(mnt_path))
+ goto out;
+
+ SAFE_MKDIR(mnt_path, 0777);
+ if (mount("cgroup2", mnt_path, "cgroup2", 0, NULL) == -1) {
+ if (errno == ENODEV) {
+ if (rmdir(mnt_path) == -1)
+ tst_res(TWARN | TERRNO, "rmdir %s failed", mnt_path);
+ tst_brk(TCONF,
+ "Cgroup v2 is not configured in kernel");
+ }
+ tst_brk(TBROK | TERRNO, "mount %s", mnt_path);
+ }
+
+out:
+ SAFE_MKDIR(new_path, 0777);
+
+ tst_res(TINFO, "Cgroup v2 mount at %s success", mnt_path);
+}
+
+static void tst_cgroupN_umount(const char *mnt_path, const char *new_path)
+{
+ FILE *fp;
+ int fd;
+ char s_new[BUFSIZ], s[BUFSIZ], value[BUFSIZ];
+ char knob_path[PATH_MAX];
+
+ if (!tst_is_mounted(mnt_path))
+ return;
+
+ /* Move all processes in task(v2: cgroup.procs) to its parent node. */
+ if (tst_cg_ver & TST_CGROUP_V1)
+ sprintf(s, "%s/tasks", mnt_path);
+ if (tst_cg_ver & TST_CGROUP_V2)
+ sprintf(s, "%s/cgroup.procs", mnt_path);
+
+ fd = open(s, O_WRONLY);
+ if (fd == -1)
+ tst_res(TWARN | TERRNO, "open %s", s);
+
+ if (tst_cg_ver & TST_CGROUP_V1)
+ snprintf(s_new, BUFSIZ, "%s/tasks", new_path);
+ if (tst_cg_ver & TST_CGROUP_V2)
+ snprintf(s_new, BUFSIZ, "%s/cgroup.procs", new_path);
+
+ fp = fopen(s_new, "r");
+ if (fp == NULL)
+ tst_res(TWARN | TERRNO, "fopen %s", s_new);
+ if ((fd != -1) && (fp != NULL)) {
+ while (fgets(value, BUFSIZ, fp) != NULL)
+ if (write(fd, value, strlen(value) - 1)
+ != (ssize_t)strlen(value) - 1)
+ tst_res(TWARN | TERRNO, "write %s", s);
+ }
+ if (tst_cg_ver & TST_CGROUP_V1) {
+ sprintf(knob_path, "%s/cpuset.cpus", mnt_path);
+ if (!access(knob_path, F_OK)) {
+ sprintf(knob_path, "%s/cgroup.clone_children", mnt_path);
+ SAFE_FILE_PRINTF(knob_path, "%d", clone_children);
+ }
+ }
+ if (fd != -1)
+ close(fd);
+ if (fp != NULL)
+ fclose(fp);
+ if (rmdir(new_path) == -1)
+ tst_res(TWARN | TERRNO, "rmdir %s", new_path);
+ if (umount(mnt_path) == -1)
+ tst_res(TWARN | TERRNO, "umount %s", mnt_path);
+ if (rmdir(mnt_path) == -1)
+ tst_res(TWARN | TERRNO, "rmdir %s", mnt_path);
+
+ if (tst_cg_ver & TST_CGROUP_V1)
+ tst_res(TINFO, "Cgroup v1 unmount success");
+ if (tst_cg_ver & TST_CGROUP_V2)
+ tst_res(TINFO, "Cgroup v2 unmount success");
+}
+
+struct tst_cgroup_path {
+ char *mnt_path;
+ char *new_path;
+ struct tst_cgroup_path *next;
+};
+
+static struct tst_cgroup_path *tst_cgroup_paths;
+
+static void tst_cgroup_set_path(const char *cgroup_dir)
+{
+ char cgroup_new_dir[PATH_MAX];
+ struct tst_cgroup_path *tst_cgroup_path, *a;
+
+ if (!cgroup_dir)
+ tst_brk(TBROK, "Invalid cgroup dir, plese check cgroup_dir");
+
+ sprintf(cgroup_new_dir, "%s/ltp_%d", cgroup_dir, rand());
+
+ /* To store cgroup path in the 'path' list */
+ tst_cgroup_path = SAFE_MALLOC(sizeof(struct tst_cgroup_path));
+ tst_cgroup_path->mnt_path = SAFE_MALLOC(strlen(cgroup_dir) + 1);
+ tst_cgroup_path->new_path = SAFE_MALLOC(strlen(cgroup_new_dir) + 1);
+ tst_cgroup_path->next = NULL;
+
+ if (!tst_cgroup_paths) {
+ tst_cgroup_paths = tst_cgroup_path;
+ } else {
+ a = tst_cgroup_paths;
+ do {
+ if (!a->next) {
+ a->next = tst_cgroup_path;
+ break;
+ }
+ a = a->next;
+ } while (a);
+ }
+
+ sprintf(tst_cgroup_path->mnt_path, "%s", cgroup_dir);
+ sprintf(tst_cgroup_path->new_path, "%s", cgroup_new_dir);
+}
+
+static char *tst_cgroup_get_path(const char *cgroup_dir)
+{
+ struct tst_cgroup_path *a;
+
+ if (!tst_cgroup_paths)
+ return NULL;
+
+ a = tst_cgroup_paths;
+
+ while (strcmp(a->mnt_path, cgroup_dir) != 0){
+ if (!a->next) {
+ tst_res(TINFO, "%s is not found", cgroup_dir);
+ return NULL;
+ }
+ a = a->next;
+ };
+
+ return a->new_path;
+}
+
+static void tst_cgroup_del_path(const char *cgroup_dir)
+{
+ struct tst_cgroup_path *a, *b;
+
+ if (!tst_cgroup_paths)
+ return;
+
+ a = b = tst_cgroup_paths;
+
+ while (strcmp(b->mnt_path, cgroup_dir) != 0) {
+ if (!b->next) {
+ tst_res(TINFO, "%s is not found", cgroup_dir);
+ return;
+ }
+ a = b;
+ b = b->next;
+ };
+
+ if (b == tst_cgroup_paths)
+ tst_cgroup_paths = b->next;
+ else
+ a->next = b->next;
+
+ free(b->mnt_path);
+ free(b->new_path);
+ free(b);
+}
+
+void tst_cgroup_mount(enum tst_cgroup_ctrl ctrl, const char *cgroup_dir)
+{
+ char *cgroup_new_dir;
+ char knob_path[PATH_MAX];
+
+ tst_cg_ver = tst_cgroup_version();
+
+ tst_cgroup_set_path(cgroup_dir);
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+
+ if (tst_cg_ver & TST_CGROUP_V1) {
+ switch(ctrl) {
+ case TST_CGROUP_MEMCG:
+ tst_cgroup1_mount("memcg", "memory", cgroup_dir, cgroup_new_dir);
+ break;
+ case TST_CGROUP_CPUSET:
+ tst_cgroup1_mount("cpusetcg", "cpuset", cgroup_dir, cgroup_new_dir);
+ break;
+ default:
+ tst_brk(TBROK, "Invalid cgroup controller: %d", ctrl);
+ }
+ }
+
+ if (tst_cg_ver & TST_CGROUP_V2) {
+ tst_cgroup2_mount(cgroup_dir, cgroup_new_dir);
+
+ switch(ctrl) {
+ case TST_CGROUP_MEMCG:
+ sprintf(knob_path, "%s/cgroup.subtree_control", cgroup_dir);
+ SAFE_FILE_PRINTF(knob_path, "%s", "+memory");
+ break;
+ case TST_CGROUP_CPUSET:
+ tst_brk(TCONF, "Cgroup v2 hasn't achieve cpuset subsystem");
+ break;
+ default:
+ tst_brk(TBROK, "Invalid cgroup controller: %d", ctrl);
+ }
+ }
+}
+
+void tst_cgroup_umount(const char *cgroup_dir)
+{
+ char *cgroup_new_dir;
+
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+ tst_cgroupN_umount(cgroup_dir, cgroup_new_dir);
+ tst_cgroup_del_path(cgroup_dir);
+}
+
+void tst_cgroup_set_knob(const char *cgroup_dir, const char *knob, long value)
+{
+ char *cgroup_new_dir;
+ char knob_path[PATH_MAX];
+
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+ sprintf(knob_path, "%s/%s", cgroup_new_dir, knob);
+ SAFE_FILE_PRINTF(knob_path, "%ld", value);
+}
+
+void tst_cgroup_move_current(const char *cgroup_dir)
+{
+ if (tst_cg_ver & TST_CGROUP_V1)
+ tst_cgroup_set_knob(cgroup_dir, "tasks", getpid());
+
+ if (tst_cg_ver & TST_CGROUP_V2)
+ tst_cgroup_set_knob(cgroup_dir, "cgroup.procs", getpid());
+}
+
+void tst_cgroup_mem_set_maxbytes(const char *cgroup_dir, long memsz)
+{
+ if (tst_cg_ver & TST_CGROUP_V1)
+ tst_cgroup_set_knob(cgroup_dir, "memory.limit_in_bytes", memsz);
+
+ if (tst_cg_ver & TST_CGROUP_V2)
+ tst_cgroup_set_knob(cgroup_dir, "memory.max", memsz);
+}
+
+int tst_cgroup_mem_swapacct_enabled(const char *cgroup_dir)
+{
+ char *cgroup_new_dir;
+ char knob_path[PATH_MAX];
+
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+
+ if (tst_cg_ver & TST_CGROUP_V1) {
+ sprintf(knob_path, "%s/%s",
+ cgroup_new_dir, "/memory.memsw.limit_in_bytes");
+
+ if ((access(knob_path, F_OK) == -1)) {
+ if (errno == ENOENT)
+ tst_res(TCONF, "memcg swap accounting is disabled");
+ else
+ tst_brk(TBROK | TERRNO, "failed to access %s", knob_path);
+ } else {
+ return 1;
+ }
+ }
+
+ if (tst_cg_ver & TST_CGROUP_V2) {
+ sprintf(knob_path, "%s/%s",
+ cgroup_new_dir, "/memory.swap.max");
+
+ if ((access(knob_path, F_OK) == -1)) {
+ if (errno == ENOENT)
+ tst_res(TCONF, "memcg swap accounting is disabled");
+ else
+ tst_brk(TBROK | TERRNO, "failed to access %s", knob_path);
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void tst_cgroup_mem_set_maxswap(const char *cgroup_dir, long memsz)
+{
+ if (tst_cg_ver & TST_CGROUP_V1)
+ tst_cgroup_set_knob(cgroup_dir, "memory.memsw.limit_in_bytes", memsz);
+
+ if (tst_cg_ver & TST_CGROUP_V2)
+ tst_cgroup_set_knob(cgroup_dir, "memory.swap.max", memsz);
+}
+
+void tst_cgroup_cpuset_read_files(const char *cgroup_dir, const char *filename, char *retbuf)
+{
+ int fd;
+ char *cgroup_new_dir;
+ char knob_path[PATH_MAX];
+
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+
+ /*
+ * try either '/dev/cpuset/XXXX' or '/dev/cpuset/cpuset.XXXX'
+ * please see Documentation/cgroups/cpusets.txt from kernel src
+ * for details
+ */
+ sprintf(knob_path, "%s/%s", cgroup_new_dir, filename);
+ fd = open(knob_path, O_RDONLY);
+ if (fd == -1) {
+ if (errno == ENOENT) {
+ sprintf(knob_path, "%s/cpuset.%s",
+ cgroup_new_dir, filename);
+ fd = SAFE_OPEN(knob_path, O_RDONLY);
+ } else
+ tst_brk(TBROK | TERRNO, "open %s", knob_path);
+ }
+
+ if (read(fd, retbuf, sizeof(retbuf)) < 0)
+ tst_brk(TBROK | TERRNO, "read %s", knob_path);
+
+ close(fd);
+}
+
+void tst_cgroup_cpuset_write_files(const char *cgroup_dir, const char *filename, const char *buf)
+{
+ int fd;
+ char *cgroup_new_dir;
+ char knob_path[PATH_MAX];
+
+ cgroup_new_dir = tst_cgroup_get_path(cgroup_dir);
+
+ /*
+ * try either '/dev/cpuset/XXXX' or '/dev/cpuset/cpuset.XXXX'
+ * please see Documentation/cgroups/cpusets.txt from kernel src
+ * for details
+ */
+ sprintf(knob_path, "%s/%s", cgroup_new_dir, filename);
+ fd = open(knob_path, O_WRONLY);
+ if (fd == -1) {
+ if (errno == ENOENT) {
+ sprintf(knob_path, "%s/cpuset.%s", cgroup_new_dir, filename);
+ fd = SAFE_OPEN(knob_path, O_WRONLY);
+ } else
+ tst_brk(TBROK | TERRNO, "open %s", knob_path);
+ }
+
+ SAFE_WRITE(1, fd, buf, strlen(buf));
+
+ close(fd);
+}
diff --git a/src/kernel/tests/lib/tst_checkpoint.c b/src/kernel/tests/lib/tst_checkpoint.c
new file mode 100644
index 0000000..5e5b114
--- /dev/null
+++ b/src/kernel/tests/lib/tst_checkpoint.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <linux/futex.h>
+
+#include "test.h"
+#include "safe_macros.h"
+#include "lapi/futex.h"
+
+#define DEFAULT_MSEC_TIMEOUT 10000
+
+futex_t *tst_futexes;
+unsigned int tst_max_futexes;
+
+void tst_checkpoint_init(const char *file, const int lineno,
+ void (*cleanup_fn)(void))
+{
+ int fd;
+ unsigned int page_size;
+
+ if (tst_futexes) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s: %d checkpoints already initialized",
+ file, lineno);
+ return;
+ }
+
+ /*
+ * The parent test process is responsible for creating the temporary
+ * directory and therefore must pass non-zero cleanup (to remove the
+ * directory if something went wrong).
+ *
+ * We cannot do this check unconditionally because if we need to init
+ * the checkpoint from a binary that was started by exec() the
+ * tst_tmpdir_created() will return false because the tmpdir was
+ * created by parent. In this case we expect the subprogram can call
+ * the init as a first function with NULL as cleanup function.
+ */
+ if (cleanup_fn && !tst_tmpdir_created()) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d You have to create test temporary directory "
+ "first (call tst_tmpdir())", file, lineno);
+ return;
+ }
+
+ page_size = getpagesize();
+
+ fd = SAFE_OPEN(cleanup_fn, "checkpoint_futex_base_file",
+ O_RDWR | O_CREAT, 0666);
+
+ SAFE_FTRUNCATE(cleanup_fn, fd, page_size);
+
+ tst_futexes = SAFE_MMAP(cleanup_fn, NULL, page_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ tst_max_futexes = page_size / sizeof(uint32_t);
+
+ SAFE_CLOSE(cleanup_fn, fd);
+}
+
+int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout)
+{
+ struct timespec timeout;
+ int ret;
+
+ if (id >= tst_max_futexes) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ timeout.tv_sec = msec_timeout/1000;
+ timeout.tv_nsec = (msec_timeout%1000) * 1000000;
+
+ do {
+ ret = syscall(SYS_futex, &tst_futexes[id], FUTEX_WAIT,
+ tst_futexes[id], &timeout);
+ } while (ret == -1 && errno == EINTR);
+
+ return ret;
+}
+
+int tst_checkpoint_wake(unsigned int id, unsigned int nr_wake,
+ unsigned int msec_timeout)
+{
+ unsigned int msecs = 0, waked = 0;
+
+ if (id >= tst_max_futexes) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ for (;;) {
+ waked += syscall(SYS_futex, &tst_futexes[id], FUTEX_WAKE,
+ INT_MAX, NULL);
+
+ if (waked == nr_wake)
+ break;
+
+ usleep(1000);
+ msecs++;
+
+ if (msecs >= msec_timeout) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void tst_safe_checkpoint_wait(const char *file, const int lineno,
+ void (*cleanup_fn)(void), unsigned int id,
+ unsigned int msec_timeout)
+{
+ int ret;
+
+ if (!msec_timeout)
+ msec_timeout = DEFAULT_MSEC_TIMEOUT;
+
+ ret = tst_checkpoint_wait(id, msec_timeout);
+
+ if (ret) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: tst_checkpoint_wait(%u, %i)",
+ file, lineno, id, msec_timeout);
+ }
+}
+
+void tst_safe_checkpoint_wake(const char *file, const int lineno,
+ void (*cleanup_fn)(void), unsigned int id,
+ unsigned int nr_wake)
+{
+ int ret = tst_checkpoint_wake(id, nr_wake, DEFAULT_MSEC_TIMEOUT);
+
+ if (ret) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "%s:%d: tst_checkpoint_wake(%u, %u, %i)",
+ file, lineno, id, nr_wake, DEFAULT_MSEC_TIMEOUT);
+ }
+}
diff --git a/src/kernel/tests/lib/tst_checksum.c b/src/kernel/tests/lib/tst_checksum.c
new file mode 100644
index 0000000..903bf3d
--- /dev/null
+++ b/src/kernel/tests/lib/tst_checksum.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. */
+
+#include "tst_checksum.h"
+
+static const uint32_t crc32c_table[] = {
+ 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
+ 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
+ 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+ 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
+ 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
+ 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+ 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
+ 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
+ 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+ 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
+ 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
+ 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+ 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
+ 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
+ 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+ 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
+ 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
+ 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+ 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
+ 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
+ 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+ 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
+ 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
+ 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+ 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
+ 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
+ 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+ 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
+ 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
+ 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+ 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
+ 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
+ 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+ 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
+ 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
+ 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+ 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
+ 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
+ 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+ 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
+ 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
+ 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+ 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
+ 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
+ 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+ 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
+ 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
+ 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+ 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
+ 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
+ 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+ 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
+ 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
+ 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+ 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
+ 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
+ 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+ 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
+ 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
+ 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+ 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
+ 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
+ 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+ 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
+};
+
+uint32_t tst_crc32c(uint8_t *buf, size_t buf_len)
+{
+ uint32_t crc = 0xffffffff;
+
+ while (buf_len--)
+ crc = crc32c_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+
+ return ~crc;
+}
diff --git a/src/kernel/tests/lib/tst_clocks.c b/src/kernel/tests/lib/tst_clocks.c
new file mode 100644
index 0000000..cdcb9fc
--- /dev/null
+++ b/src/kernel/tests/lib/tst_clocks.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <time.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_clocks.h"
+#include "lapi/syscalls.h"
+#include "lapi/posix_clocks.h"
+
+typedef int (*mysyscall)(clockid_t clk_id, void *ts);
+
+int syscall_supported_by_kernel(long sysnr)
+{
+ int ret;
+
+ ret = syscall(sysnr, 0, NULL);
+ if (ret == -1 && errno == ENOSYS)
+ return 0;
+
+ return 1;
+}
+
+int tst_clock_getres(clockid_t clk_id, struct timespec *res)
+{
+ static struct tst_ts tts = { 0, };
+ static mysyscall func;
+ int ret;
+
+#if (__NR_clock_getres_time64 != __LTP__NR_INVALID_SYSCALL)
+ if (!func && syscall_supported_by_kernel(__NR_clock_getres_time64)) {
+ func = sys_clock_getres64;
+ tts.type = TST_KERN_TIMESPEC;
+ }
+#endif
+
+ if (!func && syscall_supported_by_kernel(__NR_clock_getres)) {
+ func = sys_clock_getres;
+ tts.type = TST_KERN_OLD_TIMESPEC;
+ }
+
+ if (!func) {
+ tst_res(TCONF, "clock_getres() not available");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ ret = func(clk_id, tst_ts_get(&tts));
+ res->tv_sec = tst_ts_get_sec(tts);
+ res->tv_nsec = tst_ts_get_nsec(tts);
+ return ret;
+}
+
+int tst_clock_gettime(clockid_t clk_id, struct timespec *ts)
+{
+ static struct tst_ts tts = { 0, };
+ static mysyscall func;
+ int ret;
+
+#if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL)
+ if (!func && syscall_supported_by_kernel(__NR_clock_gettime64)) {
+ func = sys_clock_gettime64;
+ tts.type = TST_KERN_TIMESPEC;
+ }
+#endif
+
+ if (!func && syscall_supported_by_kernel(__NR_clock_gettime)) {
+ func = sys_clock_gettime;
+ tts.type = TST_KERN_OLD_TIMESPEC;
+ }
+
+ if (!func) {
+ tst_res(TCONF, "clock_gettime() not available");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ ret = func(clk_id, tst_ts_get(&tts));
+ ts->tv_sec = tst_ts_get_sec(tts);
+ ts->tv_nsec = tst_ts_get_nsec(tts);
+ return ret;
+}
+
+int tst_clock_settime(clockid_t clk_id, struct timespec *ts)
+{
+ static struct tst_ts tts = { 0, };
+ static mysyscall func;
+
+#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL)
+ if (!func && syscall_supported_by_kernel(__NR_clock_settime64)) {
+ func = sys_clock_settime64;
+ tts.type = TST_KERN_TIMESPEC;
+ }
+#endif
+
+ if (!func && syscall_supported_by_kernel(__NR_clock_settime)) {
+ func = sys_clock_settime;
+ tts.type = TST_KERN_OLD_TIMESPEC;
+ }
+
+ if (!func) {
+ tst_res(TCONF, "clock_settime() not available");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ tst_ts_set_sec(&tts, ts->tv_sec);
+ tst_ts_set_nsec(&tts, ts->tv_nsec);
+ return func(clk_id, tst_ts_get(&tts));
+}
+
+const char *tst_clock_name(clockid_t clk_id)
+{
+ switch (clk_id) {
+ case CLOCK_REALTIME:
+ return "CLOCK_REALTIME";
+ case CLOCK_MONOTONIC:
+ return "CLOCK_MONOTONIC";
+ case CLOCK_PROCESS_CPUTIME_ID:
+ return "CLOCK_PROCESS_CPUTIME_ID";
+ case CLOCK_THREAD_CPUTIME_ID:
+ return "CLOCK_THREAD_CPUTIME_ID";
+ case CLOCK_MONOTONIC_RAW:
+ return "CLOCK_MONOTONIC_RAW";
+ case CLOCK_REALTIME_COARSE:
+ return "CLOCK_REALTIME_COARSE";
+ case CLOCK_MONOTONIC_COARSE:
+ return "CLOCK_MONOTONIC_COARSE";
+ case CLOCK_BOOTTIME:
+ return "CLOCK_BOOTTIME";
+ case CLOCK_REALTIME_ALARM:
+ return "CLOCK_REALTIME_ALARM";
+ case CLOCK_BOOTTIME_ALARM:
+ return "CLOCK_BOOTTIME_ALARM";
+ case CLOCK_TAI:
+ return "CLOCK_TAI";
+ default:
+ return "INVALID/UNKNOWN CLOCK";
+ }
+}
diff --git a/src/kernel/tests/lib/tst_cmd.c b/src/kernel/tests/lib/tst_cmd.c
new file mode 100644
index 0000000..7446249
--- /dev/null
+++ b/src/kernel/tests/lib/tst_cmd.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include "test.h"
+#include "tst_cmd.h"
+
+#define OPEN_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+#define OPEN_FLAGS (O_WRONLY | O_APPEND | O_CREAT)
+
+int tst_cmd_fds_(void (cleanup_fn)(void),
+ const char *const argv[],
+ int stdout_fd,
+ int stderr_fd,
+ enum tst_cmd_flags flags)
+{
+ int rc;
+
+ if (argv == NULL || argv[0] == NULL) {
+ tst_brkm(TBROK, cleanup_fn,
+ "argument list is empty at %s:%d", __FILE__, __LINE__);
+ return -1;
+ }
+
+ /*
+ * The tst_sig() install poisoned signal handlers for all signals the
+ * test is not expected to get.
+ *
+ * So we temporarily disable the handler for sigchild we get after our
+ * child exits so that we don't have to disable it in each test that
+ * uses this interface.
+ */
+ void *old_handler = signal(SIGCHLD, SIG_DFL);
+
+ char path[PATH_MAX];
+
+ if (tst_get_path(argv[0], path, sizeof(path))) {
+ if (flags & TST_CMD_TCONF_ON_MISSING)
+ tst_brkm(TCONF, cleanup_fn, "Couldn't find '%s' in $PATH at %s:%d", argv[0],
+ __FILE__, __LINE__);
+ else
+ return 255;
+ }
+
+ pid_t pid = vfork();
+ if (pid == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn, "vfork failed at %s:%d",
+ __FILE__, __LINE__);
+ return -1;
+ }
+ if (!pid) {
+ /* redirecting stdout and stderr if needed */
+ if (stdout_fd != -1) {
+ close(STDOUT_FILENO);
+ dup2(stdout_fd, STDOUT_FILENO);
+ }
+
+ if (stderr_fd != -1) {
+ close(STDERR_FILENO);
+ dup2(stderr_fd, STDERR_FILENO);
+ }
+
+ execvp(argv[0], (char *const *)argv);
+ _exit(254);
+ }
+
+ int ret = -1;
+ if (waitpid(pid, &ret, 0) != pid) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn, "waitpid failed at %s:%d",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ signal(SIGCHLD, old_handler);
+
+ if (!WIFEXITED(ret)) {
+ tst_brkm(TBROK, cleanup_fn, "failed to exec cmd '%s' at %s:%d",
+ argv[0], __FILE__, __LINE__);
+ return -1;
+ }
+
+ rc = WEXITSTATUS(ret);
+
+ if (!(flags & TST_CMD_PASS_RETVAL) && rc) {
+ tst_brkm(TBROK, cleanup_fn,
+ "'%s' exited with a non-zero code %d at %s:%d",
+ argv[0], rc, __FILE__, __LINE__);
+ return -1;
+ }
+
+ return rc;
+}
+
+int tst_cmd_(void (cleanup_fn)(void),
+ const char *const argv[],
+ const char *stdout_path,
+ const char *stderr_path,
+ enum tst_cmd_flags flags)
+{
+ int stdout_fd = -1;
+ int stderr_fd = -1;
+ int rc;
+
+ if (stdout_path != NULL) {
+ stdout_fd = open(stdout_path,
+ OPEN_FLAGS, OPEN_MODE);
+
+ if (stdout_fd == -1)
+ tst_resm(TWARN | TERRNO,
+ "open() on %s failed at %s:%d",
+ stdout_path, __FILE__, __LINE__);
+ }
+
+ if (stderr_path != NULL) {
+ stderr_fd = open(stderr_path,
+ OPEN_FLAGS, OPEN_MODE);
+
+ if (stderr_fd == -1)
+ tst_resm(TWARN | TERRNO,
+ "open() on %s failed at %s:%d",
+ stderr_path, __FILE__, __LINE__);
+ }
+
+ rc = tst_cmd_fds(cleanup_fn, argv, stdout_fd, stderr_fd, flags);
+
+ if ((stdout_fd != -1) && (close(stdout_fd) == -1))
+ tst_resm(TWARN | TERRNO,
+ "close() on %s failed at %s:%d",
+ stdout_path, __FILE__, __LINE__);
+
+ if ((stderr_fd != -1) && (close(stderr_fd) == -1))
+ tst_resm(TWARN | TERRNO,
+ "close() on %s failed at %s:%d",
+ stderr_path, __FILE__, __LINE__);
+
+ return rc;
+}
+
+int tst_system(const char *command)
+{
+ int ret = 0;
+
+ /*
+ *Temporarily disable SIGCHLD of user defined handler, so the
+ *system(3) function will not cause unexpected SIGCHLD signal
+ *callback function for test cases.
+ */
+ void *old_handler = signal(SIGCHLD, SIG_DFL);
+
+ ret = system(command);
+
+ signal(SIGCHLD, old_handler);
+ return ret;
+}
diff --git a/src/kernel/tests/lib/tst_coredump.c b/src/kernel/tests/lib/tst_coredump.c
new file mode 100644
index 0000000..83aa2c3
--- /dev/null
+++ b/src/kernel/tests/lib/tst_coredump.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ */
+
+#define TST_NO_DEFAULT_MAIN
+
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "tst_test.h"
+#include "tst_coredump.h"
+
+void tst_no_corefile(int verbose)
+{
+ struct rlimit new_r, old_r;
+
+ SAFE_GETRLIMIT(RLIMIT_CORE, &old_r);
+ if (old_r.rlim_max >= 1 || geteuid() == 0) {
+ /*
+ * 1 is a special value, that disables core-to-pipe.
+ * At the same time it is small enough value for
+ * core-to-file, so it skips creating cores as well.
+ */
+ new_r.rlim_cur = 1;
+ new_r.rlim_max = 1;
+ SAFE_SETRLIMIT(RLIMIT_CORE, &new_r);
+
+ if (verbose) {
+ tst_res(TINFO,
+ "Avoid dumping corefile for process(pid=%d)",
+ getpid());
+ }
+ }
+}
diff --git a/src/kernel/tests/lib/tst_cpu.c b/src/kernel/tests/lib/tst_cpu.c
new file mode 100644
index 0000000..033155e
--- /dev/null
+++ b/src/kernel/tests/lib/tst_cpu.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 Fujitsu Ltd.
+ * Author: Wanlong Gao <gaowanlong@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "test.h"
+#include "safe_macros.h"
+
+long tst_ncpus(void)
+{
+ long ncpus = -1;
+#ifdef _SC_NPROCESSORS_ONLN
+ ncpus = SAFE_SYSCONF(NULL, _SC_NPROCESSORS_ONLN);
+#else
+ tst_brkm(TBROK, NULL, "could not determine number of CPUs online");
+#endif
+ return ncpus;
+}
+
+long tst_ncpus_conf(void)
+{
+ long ncpus_conf = -1;
+#ifdef _SC_NPROCESSORS_CONF
+ ncpus_conf = SAFE_SYSCONF(NULL, _SC_NPROCESSORS_CONF);
+#else
+ tst_brkm(TBROK, NULL, "could not determine number of CPUs configured");
+#endif
+ return ncpus_conf;
+}
+
+#define KERNEL_MAX "/sys/devices/system/cpu/kernel_max"
+
+long tst_ncpus_max(void)
+{
+ long ncpus_max = -1;
+ struct stat buf;
+
+ /* sched_getaffinity() and sched_setaffinity() cares about number of
+ * possible CPUs the OS or hardware can support, which can be larger
+ * than what sysconf(_SC_NPROCESSORS_CONF) currently provides
+ * (by enumarating /sys/devices/system/cpu/cpu* entries).
+ *
+ * Use /sys/devices/system/cpu/kernel_max, if available. This
+ * represents NR_CPUS-1, a compile time option which specifies
+ * "maximum number of CPUs which this kernel will support".
+ * This should provide cpu mask size large enough for any purposes. */
+ if (stat(KERNEL_MAX, &buf) == 0) {
+ SAFE_FILE_SCANF(NULL, KERNEL_MAX, "%ld", &ncpus_max);
+ /* this is maximum CPU index allowed by the kernel
+ * configuration, so # of cpus allowed by config is +1 */
+ ncpus_max++;
+ } else {
+ /* fall back to _SC_NPROCESSORS_CONF */
+ ncpus_max = tst_ncpus_conf();
+ }
+ return ncpus_max;
+}
diff --git a/src/kernel/tests/lib/tst_crypto.c b/src/kernel/tests/lib/tst_crypto.c
new file mode 100644
index 0000000..685e087
--- /dev/null
+++ b/src/kernel/tests/lib/tst_crypto.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Richard Palethorpe <rpalethorpe@suse.com>
+ * Nicolai Stange <nstange@suse.de>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_crypto.h"
+#include "tst_netlink.h"
+
+void tst_crypto_open(struct tst_crypto_session *ses)
+{
+ TEST(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO));
+ if (TST_RET < 0 && TST_ERR == EPROTONOSUPPORT)
+ tst_brk(TCONF | TTERRNO, "NETLINK_CRYPTO is probably disabled");
+
+ if (TST_RET < 0) {
+ tst_brk(TBROK | TTERRNO,
+ "socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CRYPTO)");
+ }
+
+ ses->fd = TST_RET;
+ ses->seq_num = 0;
+}
+
+void tst_crypto_close(struct tst_crypto_session *ses)
+{
+ SAFE_CLOSE(ses->fd);
+}
+
+static int tst_crypto_recv_ack(struct tst_crypto_session *ses)
+{
+ uint32_t len;
+ char buf[BUFSIZ];
+ struct nlmsghdr *nh;
+
+ len = SAFE_NETLINK_RECV(ses->fd, buf, sizeof(buf));
+
+ for (nh = (struct nlmsghdr *) buf;
+ NLMSG_OK(nh, len);
+ nh = NLMSG_NEXT(nh, len)) {
+ if (nh->nlmsg_seq != ses->seq_num) {
+ tst_brk(TBROK,
+ "Message out of sequence; type=0%hx, seq_num=%u (not %u)",
+ nh->nlmsg_type, nh->nlmsg_seq, ses->seq_num);
+ }
+
+ /* Acks use the error message type with error number set to
+ * zero. Ofcourse we could also receive an actual error.
+ */
+ if (nh->nlmsg_type == NLMSG_ERROR)
+ return ((struct nlmsgerr *)NLMSG_DATA(nh))->error;
+
+ tst_brk(TBROK, "Unexpected message type; type=0x%hx, seq_num=%u",
+ nh->nlmsg_type, nh->nlmsg_seq);
+ }
+
+ tst_brk(TBROK, "Empty message from netlink socket?");
+
+ return ENODATA;
+}
+
+int tst_crypto_add_alg(struct tst_crypto_session *ses,
+ const struct crypto_user_alg *alg)
+{
+ struct nlmsghdr nh = {
+ .nlmsg_len = sizeof(struct nlmsghdr) + sizeof(*alg),
+ .nlmsg_type = CRYPTO_MSG_NEWALG,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ .nlmsg_seq = ++(ses->seq_num),
+ .nlmsg_pid = 0,
+ };
+
+ SAFE_NETLINK_SEND(ses->fd, &nh, alg);
+
+ return tst_crypto_recv_ack(ses);
+}
+
+int tst_crypto_del_alg(struct tst_crypto_session *ses,
+ const struct crypto_user_alg *alg)
+{
+ unsigned int i = 0;
+ struct nlmsghdr nh = {
+ .nlmsg_len = sizeof(struct nlmsghdr) + sizeof(*alg),
+ .nlmsg_type = CRYPTO_MSG_DELALG,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ .nlmsg_pid = 0,
+ };
+
+ while (1) {
+ nh.nlmsg_seq = ++(ses->seq_num),
+
+ SAFE_NETLINK_SEND(ses->fd, &nh, alg);
+
+ TEST(tst_crypto_recv_ack(ses));
+ if (TST_RET != -EBUSY || i >= ses->retries)
+ break;
+
+ if (usleep(1) && errno != EINTR)
+ tst_brk(TBROK | TERRNO, "usleep(1)");
+
+ ++i;
+ }
+
+ return TST_RET;
+}
diff --git a/src/kernel/tests/lib/tst_device.c b/src/kernel/tests/lib/tst_device.c
new file mode 100644
index 0000000..0df8efe
--- /dev/null
+++ b/src/kernel/tests/lib/tst_device.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2014 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <uapi_xloop.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/sysmacros.h>
+#include "lapi/syscalls.h"
+#include "test.h"
+#include "safe_macros.h"
+
+#ifndef XLOOP_CTL_GET_FREE
+# define XLOOP_CTL_GET_FREE 0x4C82
+#endif
+
+#define XLOOP_CONTROL_FILE "/dev/xloop-control"
+
+#define DEV_FILE "test_dev.img"
+#define DEV_SIZE_MB 256u
+
+static char dev_path[1024];
+static int device_acquired;
+static unsigned long prev_dev_sec_write;
+
+static const char *dev_variants[] = {
+ "/dev/xloop%i",
+ "/dev/xloop/%i",
+ "/dev/block/xloop%i"
+};
+
+static int set_dev_path(int dev, char *path, size_t path_len)
+{
+ unsigned int i;
+ struct stat st;
+
+ for (i = 0; i < ARRAY_SIZE(dev_variants); i++) {
+ snprintf(path, path_len, dev_variants[i], dev);
+
+ if (stat(path, &st) == 0 && S_ISBLK(st.st_mode))
+ return 1;
+ }
+
+ return 0;
+}
+
+int tst_find_free_xloopdev(char *path, size_t path_len)
+{
+ int ctl_fd, dev_fd, rc, i;
+ struct xloop_info xloopinfo;
+ char buf[1024];
+
+ /* since Linux 3.1 */
+ ctl_fd = open(XLOOP_CONTROL_FILE, O_RDWR);
+
+ if (ctl_fd > 0) {
+ rc = ioctl(ctl_fd, XLOOP_CTL_GET_FREE);
+ close(ctl_fd);
+ if (rc >= 0) {
+ if (path)
+ set_dev_path(rc, path, path_len);
+ tst_resm(TINFO, "Found free device %d '%s'",
+ rc, path ?: "");
+ return rc;
+ }
+ tst_resm(TINFO, "Couldn't find free xloop device");
+ return -1;
+ }
+
+ switch (errno) {
+ case ENOENT:
+ break;
+ case EACCES:
+ tst_resm(TINFO | TERRNO,
+ "Not allowed to open " XLOOP_CONTROL_FILE ". "
+ "Are you root?");
+ break;
+ default:
+ tst_resm(TBROK | TERRNO, "Failed to open " XLOOP_CONTROL_FILE);
+ }
+
+ /*
+ * Older way is to iterate over /dev/xloop%i and /dev/xloop/%i and try
+ * XLOOP_GET_STATUS ioctl() which fails for free xloop devices.
+ */
+ for (i = 0; i < 256; i++) {
+
+ if (!set_dev_path(i, buf, sizeof(buf)))
+ continue;
+
+ dev_fd = open(buf, O_RDONLY);
+
+ if (dev_fd < 0)
+ continue;
+
+ if (ioctl(dev_fd, XLOOP_GET_STATUS, &xloopinfo) == 0) {
+ tst_resm(TINFO, "Device '%s' in use", buf);
+ } else {
+ if (errno != ENXIO)
+ continue;
+ tst_resm(TINFO, "Found free device '%s'", buf);
+ close(dev_fd);
+ if (path != NULL) {
+ strncpy(path, buf, path_len);
+ path[path_len-1] = '\0';
+ }
+ return i;
+ }
+
+ close(dev_fd);
+ }
+
+ tst_resm(TINFO, "No free devices found");
+
+ return -1;
+}
+
+int tst_attach_device(const char *dev, const char *file)
+{
+ int dev_fd, file_fd;
+ struct xloop_info xloopinfo;
+
+ dev_fd = open(dev, O_RDWR);
+ if (dev_fd < 0) {
+ tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", dev);
+ return 1;
+ }
+
+ file_fd = open(file, O_RDWR);
+ if (file_fd < 0) {
+ tst_resm(TWARN | TERRNO, "open('%s', O_RDWR) failed", file);
+ close(dev_fd);
+ return 1;
+ }
+
+ if (ioctl(dev_fd, XLOOP_SET_FD, file_fd) < 0) {
+ close(dev_fd);
+ close(file_fd);
+ tst_resm(TWARN | TERRNO, "ioctl(%s, XLOOP_SET_FD, %s) failed",
+ dev, file);
+ return 1;
+ }
+
+ /* Old mkfs.btrfs use XLOOP_GET_STATUS instead of backing_file to get
+ * associated filename, so we need to set up the device by calling
+ * XLOOP_SET_FD and XLOOP_SET_STATUS.
+ */
+ memset(&xloopinfo, 0, sizeof(xloopinfo));
+ strcpy(xloopinfo.xlo_name, file);
+
+ if (ioctl(dev_fd, XLOOP_SET_STATUS, &xloopinfo)) {
+ close(dev_fd);
+ close(file_fd);
+ tst_resm(TWARN | TERRNO,
+ "ioctl(%s, XLOOP_SET_STATUS, %s) failed", dev, file);
+ return 1;
+ }
+
+ close(dev_fd);
+ close(file_fd);
+ return 0;
+}
+
+int tst_detach_device_by_fd(const char *dev, int dev_fd)
+{
+ int ret, i;
+
+ /* keep trying to clear XLOOPDEV until we get ENXIO, a quick succession
+ * of attach/detach might not give udev enough time to complete */
+ for (i = 0; i < 40; i++) {
+ ret = ioctl(dev_fd, XLOOP_CLR_FD, 0);
+
+ if (ret && (errno == ENXIO))
+ return 0;
+
+ if (ret && (errno != EBUSY)) {
+ tst_resm(TWARN,
+ "ioctl(%s, XLOOP_CLR_FD, 0) unexpectedly failed with: %s",
+ dev, tst_strerrno(errno));
+ return 1;
+ }
+
+ usleep(50000);
+ }
+
+ tst_resm(TWARN,
+ "ioctl(%s, XLOOP_CLR_FD, 0) no ENXIO for too long", dev);
+ return 1;
+}
+
+int tst_detach_device(const char *dev)
+{
+ int dev_fd, ret;
+
+ dev_fd = open(dev, O_RDONLY);
+ if (dev_fd < 0) {
+ tst_resm(TWARN | TERRNO, "open(%s) failed", dev);
+ return 1;
+ }
+
+ ret = tst_detach_device_by_fd(dev, dev_fd);
+ close(dev_fd);
+ return ret;
+}
+
+int tst_dev_sync(int fd)
+{
+ return syscall(__NR_syncfs, fd);
+}
+
+const char *tst_acquire_xloop_device(unsigned int size, const char *filename)
+{
+ unsigned int acq_dev_size = MAX(size, DEV_SIZE_MB);
+
+ if (tst_prealloc_file(filename, 1024 * 1024, acq_dev_size)) {
+ tst_resm(TWARN | TERRNO, "Failed to create %s", filename);
+ return NULL;
+ }
+
+ if (tst_find_free_xloopdev(dev_path, sizeof(dev_path)) == -1)
+ return NULL;
+
+ if (tst_attach_device(dev_path, filename))
+ return NULL;
+
+ return dev_path;
+}
+
+const char *tst_acquire_device__(unsigned int size)
+{
+ int fd;
+ const char *dev;
+ struct stat st;
+ unsigned int acq_dev_size;
+ uint64_t ltp_dev_size;
+
+ acq_dev_size = MAX(size, DEV_SIZE_MB);
+
+ dev = getenv("LTP_DEV");
+
+ if (dev) {
+ tst_resm(TINFO, "Using test device LTP_DEV='%s'", dev);
+
+ if (stat(dev, &st)) {
+ tst_resm(TWARN | TERRNO, "stat() failed");
+ return NULL;
+ }
+
+ if (!S_ISBLK(st.st_mode)) {
+ tst_resm(TWARN, "%s is not a block device", dev);
+ return NULL;
+ }
+
+ fd = open(dev, O_RDONLY);
+ if (fd < 0) {
+ tst_resm(TWARN | TERRNO,
+ "open(%s, O_RDONLY) failed", dev);
+ return NULL;
+ }
+
+ if (ioctl(fd, BLKGETSIZE64, &ltp_dev_size)) {
+ tst_resm(TWARN | TERRNO,
+ "ioctl(fd, BLKGETSIZE64, ...) failed");
+ close(fd);
+ return NULL;
+ }
+
+ if (close(fd)) {
+ tst_resm(TWARN | TERRNO,
+ "close(fd) failed");
+ return NULL;
+ }
+
+ ltp_dev_size = ltp_dev_size/1024/1024;
+
+ if (acq_dev_size <= ltp_dev_size)
+ return dev;
+
+ tst_resm(TINFO, "Skipping $LTP_DEV size %"PRIu64"MB, requested size %uMB",
+ ltp_dev_size, acq_dev_size);
+ }
+
+ dev = tst_acquire_xloop_device(acq_dev_size, DEV_FILE);
+
+ if (dev)
+ device_acquired = 1;
+
+ return dev;
+}
+
+const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size)
+{
+ const char *device;
+
+ if (device_acquired) {
+ tst_brkm(TBROK, cleanup_fn, "Device already acquired");
+ return NULL;
+ }
+
+ if (!tst_tmpdir_created()) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Cannot acquire device without tmpdir() created");
+ return NULL;
+ }
+
+ device = tst_acquire_device__(size);
+
+ if (!device) {
+ tst_brkm(TBROK, cleanup_fn, "Failed to acquire device");
+ return NULL;
+ }
+
+ return device;
+}
+
+int tst_release_device(const char *dev)
+{
+ int ret;
+
+ if (!device_acquired)
+ return 0;
+
+ /*
+ * Loop device was created -> we need to detach it.
+ *
+ * The file image is deleted in tst_rmdir();
+ */
+ ret = tst_detach_device(dev);
+
+ device_acquired = 0;
+
+ return ret;
+}
+
+int tst_clear_device(const char *dev)
+{
+ if (tst_fill_file(dev, 0, 1024, 512)) {
+ tst_resm(TWARN, "Failed to clear 512k block on %s", dev);
+ return 1;
+ }
+
+ return 0;
+}
+
+int tst_umount(const char *path)
+{
+ int err, ret, i;
+
+ for (i = 0; i < 50; i++) {
+ ret = umount(path);
+ err = errno;
+
+ if (!ret)
+ return 0;
+
+ if (err != EBUSY) {
+ tst_resm(TWARN, "umount('%s') failed with %s",
+ path, tst_strerrno(err));
+ errno = err;
+ return ret;
+ }
+
+ tst_resm(TINFO, "umount('%s') failed with %s, try %2i...",
+ path, tst_strerrno(err), i+1);
+
+ if (i == 0) {
+ tst_resm(TINFO, "Likely gvfsd-trash is probing newly "
+ "mounted fs, kill it to speed up tests.");
+ }
+
+ usleep(100000);
+ }
+
+ tst_resm(TWARN, "Failed to umount('%s') after 50 retries", path);
+ errno = err;
+ return -1;
+}
+
+int tst_is_mounted(const char *path)
+{
+ char line[PATH_MAX];
+ FILE *file;
+ int ret = 0;
+
+ file = SAFE_FOPEN(NULL, "/proc/mounts", "r");
+
+ while (fgets(line, sizeof(line), file)) {
+ if (strstr(line, path) != NULL) {
+ ret = 1;
+ break;
+ }
+ }
+
+ SAFE_FCLOSE(NULL, file);
+
+ if (!ret)
+ tst_resm(TINFO, "No device is mounted at %s", path);
+
+ return ret;
+}
+
+int tst_is_mounted_at_tmpdir(const char *path)
+{
+ char cdir[PATH_MAX], mpath[PATH_MAX];
+ int ret;
+
+ if (!getcwd(cdir, PATH_MAX)) {
+ tst_resm(TWARN | TERRNO, "Failed to find current directory");
+ return 0;
+ }
+
+ ret = snprintf(mpath, PATH_MAX, "%s/%s", cdir, path);
+ if (ret < 0 || ret >= PATH_MAX) {
+ tst_resm(TWARN | TERRNO,
+ "snprintf() should have returned %d instead of %d",
+ PATH_MAX, ret);
+ return 0;
+ }
+
+ return tst_is_mounted(mpath);
+}
+
+int find_stat_file(const char *dev, char *path, size_t path_len)
+{
+ const char *devname = strrchr(dev, '/') + 1;
+
+ snprintf(path, path_len, "/sys/block/%s/stat", devname);
+
+ if (!access(path, F_OK))
+ return 1;
+
+ DIR *dir = SAFE_OPENDIR(NULL, "/sys/block/");
+ struct dirent *ent;
+
+ while ((ent = readdir(dir))) {
+ snprintf(path, path_len, "/sys/block/%s/%s/stat", ent->d_name, devname);
+
+ if (!access(path, F_OK)) {
+ SAFE_CLOSEDIR(NULL, dir);
+ return 1;
+ }
+ }
+
+ SAFE_CLOSEDIR(NULL, dir);
+ return 0;
+}
+
+unsigned long tst_dev_bytes_written(const char *dev)
+{
+ unsigned long dev_sec_write = 0, dev_bytes_written, io_ticks = 0;
+ char dev_stat_path[1024];
+
+ if (!find_stat_file(dev, dev_stat_path, sizeof(dev_stat_path)))
+ tst_brkm(TCONF, NULL, "Test device stat file: %s not found",
+ dev_stat_path);
+
+ SAFE_FILE_SCANF(NULL, dev_stat_path,
+ "%*s %*s %*s %*s %*s %*s %lu %*s %*s %lu",
+ &dev_sec_write, &io_ticks);
+
+ if (!io_ticks)
+ tst_brkm(TCONF, NULL, "Test device stat file: %s broken",
+ dev_stat_path);
+
+ dev_bytes_written = (dev_sec_write - prev_dev_sec_write) * 512;
+
+ prev_dev_sec_write = dev_sec_write;
+
+ return dev_bytes_written;
+}
+
+void tst_find_backing_dev(const char *path, char *dev)
+{
+ char fmt[20];
+ struct stat buf;
+ FILE *file;
+ char line[PATH_MAX];
+ char *pre = NULL;
+ char *next = NULL;
+
+ if (stat(path, &buf) < 0)
+ tst_brkm(TWARN | TERRNO, NULL, "stat() failed");
+
+ snprintf(fmt, sizeof(fmt), "%u:%u", major(buf.st_dev), minor(buf.st_dev));
+ file = SAFE_FOPEN(NULL, "/proc/self/mountinfo", "r");
+
+ while (fgets(line, sizeof(line), file)) {
+ if (strstr(line, fmt) != NULL) {
+ pre = strstr(line, " - ");
+ pre = strtok_r(pre, " ", &next);
+ pre = strtok_r(NULL, " ", &next);
+ pre = strtok_r(NULL, " ", &next);
+ strcpy(dev, pre);
+ break;
+ }
+ }
+
+ SAFE_FCLOSE(NULL, file);
+
+ if (stat(dev, &buf) < 0)
+ tst_brkm(TWARN | TERRNO, NULL, "stat(%s) failed", dev);
+
+ if (S_ISBLK(buf.st_mode) != 1)
+ tst_brkm(TCONF, NULL, "dev(%s) isn't a block dev", dev);
+}
diff --git a/src/kernel/tests/lib/tst_dir_is_empty.c b/src/kernel/tests/lib/tst_dir_is_empty.c
new file mode 100644
index 0000000..43764ee
--- /dev/null
+++ b/src/kernel/tests/lib/tst_dir_is_empty.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "test.h"
+#include "safe_macros.h"
+
+int tst_dir_is_empty_(void (cleanup_fn)(void), const char *name, int verbose)
+{
+ struct dirent *entry;
+ DIR *dir = SAFE_OPENDIR(cleanup_fn, name);
+ int ret = 1;
+
+ while ((entry = SAFE_READDIR(cleanup_fn, dir)) != NULL) {
+ const char *file = entry->d_name;
+
+ if (!strcmp(file, "..") || !strcmp(file, "."))
+ continue;
+
+ if (verbose)
+ tst_resm(TINFO, "found a file: %s", file);
+ ret = 0;
+ break;
+ }
+
+ SAFE_CLOSEDIR(cleanup_fn, dir);
+
+ return ret;
+}
diff --git a/src/kernel/tests/lib/tst_fill_file.c b/src/kernel/tests/lib/tst_fill_file.c
new file mode 100644
index 0000000..8047200
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fill_file.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Stanislav Kholmanskikh <stanislav.kholmanskikh@oracle.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "lapi/fallocate.h"
+
+#include "test.h"
+
+int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount)
+{
+ size_t i;
+ char *buf;
+
+ /* Filling a memory buffer with provided pattern */
+ buf = malloc(bs);
+ if (buf == NULL)
+ return -1;
+
+ for (i = 0; i < bs; i++)
+ buf[i] = pattern;
+
+ /* Filling the file */
+ for (i = 0; i < bcount; i++) {
+ if (write(fd, buf, bs) != (ssize_t)bs) {
+ free(buf);
+ return -1;
+ }
+ }
+
+ free(buf);
+
+ return 0;
+}
+
+int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount)
+{
+ int ret;
+
+ errno = 0;
+ ret = fallocate(fd, 0, 0, bs * bcount);
+
+ if (ret && errno == ENOSPC)
+ return ret;
+
+ if (ret)
+ ret = tst_fill_fd(fd, 0, bs, bcount);
+
+ return ret;
+}
+
+int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount)
+{
+ int fd;
+
+ fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (fd < 0)
+ return -1;
+
+ if (tst_fill_fd(fd, pattern, bs, bcount)) {
+ close(fd);
+ unlink(path);
+ return -1;
+ }
+
+ if (close(fd) < 0) {
+ unlink(path);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int tst_prealloc_file(const char *path, size_t bs, size_t bcount)
+{
+ int fd;
+
+ fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (fd < 0)
+ return -1;
+
+ if (tst_prealloc_size_fd(fd, bs, bcount)) {
+ close(fd);
+ unlink(path);
+ return -1;
+ }
+
+ if (close(fd) < 0) {
+ unlink(path);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/kernel/tests/lib/tst_fill_fs.c b/src/kernel/tests/lib/tst_fill_fs.c
new file mode 100644
index 0000000..121dd2f
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fill_fs.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/statvfs.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_fs.h"
+
+void tst_fill_fs(const char *path, int verbose)
+{
+ int i = 0;
+ char file[PATH_MAX];
+ char buf[4096];
+ size_t len;
+ ssize_t ret;
+ int fd;
+ struct statvfs fi;
+ statvfs(path, &fi);
+
+ for (;;) {
+ len = random() % (1024 * 102400);
+
+ snprintf(file, sizeof(file), "%s/file%i", path, i++);
+
+ if (verbose)
+ tst_res(TINFO, "Creating file %s size %zu", file, len);
+
+ fd = open(file, O_WRONLY | O_CREAT, 0700);
+ if (fd == -1) {
+ if (errno != ENOSPC)
+ tst_brk(TBROK | TERRNO, "open()");
+
+ tst_res(TINFO | TERRNO, "open()");
+ return;
+ }
+
+ while (len) {
+ ret = write(fd, buf, MIN(len, sizeof(buf)));
+
+ if (ret < 0) {
+ /* retry on ENOSPC to make sure filesystem is really full */
+ if (errno == ENOSPC && len >= fi.f_bsize/2) {
+ SAFE_FSYNC(fd);
+ len /= 2;
+ continue;
+ }
+
+ SAFE_CLOSE(fd);
+
+ if (errno != ENOSPC)
+ tst_brk(TBROK | TERRNO, "write()");
+
+ tst_res(TINFO | TERRNO, "write()");
+ return;
+ }
+
+ len -= ret;
+ }
+
+ SAFE_CLOSE(fd);
+ }
+}
diff --git a/src/kernel/tests/lib/tst_fs_has_free.c b/src/kernel/tests/lib/tst_fs_has_free.c
new file mode 100644
index 0000000..e82dfa8
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fs_has_free.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 Fujitsu Ltd.
+ * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * DESCRIPTION
+ * Check if the mounted file system has enough free space,
+ * if it is, tst_fs_has_free() returns 1, otherwise 0.
+ */
+
+#include <stdint.h>
+#include <sys/vfs.h>
+#include "test.h"
+#include "tst_fs.h"
+
+int tst_fs_has_free_(void (*cleanup)(void), const char *path,
+ unsigned int size, unsigned int mult)
+{
+ struct statfs sf;
+
+ if (statfs(path, &sf)) {
+ tst_brkm(TBROK | TERRNO, cleanup,
+ "tst_fs_has_free: failed to statfs(%s)", path);
+ return 0;
+ }
+
+ if ((uint64_t)sf.f_bavail * sf.f_bsize >= (uint64_t)size * mult)
+ return 1;
+
+ return 0;
+}
diff --git a/src/kernel/tests/lib/tst_fs_link_count.c b/src/kernel/tests/lib/tst_fs_link_count.c
new file mode 100644
index 0000000..860510d
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fs_link_count.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2014 Fujitsu Ltd.
+ * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "test.h"
+#include "usctest.h"
+#include "safe_macros.h"
+
+#define MAX_SANE_HARD_LINKS 65535
+
+/*
+ * filesystems whose subdir limit is less than MAX_SANE_HARD_LINKS
+ * XXX: we cannot filter ext4 out, because ext2/ext3/ext4 have the
+ * same magic number
+ */
+const long subdir_limit_whitelist[] = {
+ TST_EXT2_OLD_MAGIC, TST_EXT234_MAGIC, TST_MINIX_MAGIC,
+ TST_MINIX_MAGIC2, TST_MINIX2_MAGIC, TST_MINIX2_MAGIC2,
+ TST_MINIX3_MAGIC, TST_UDF_MAGIC, TST_SYSV2_MAGIC,
+ TST_SYSV4_MAGIC, TST_UFS_MAGIC, TST_UFS2_MAGIC,
+ TST_F2FS_MAGIC, TST_NILFS_MAGIC, TST_EXOFS_MAGIC
+};
+
+int tst_fs_fill_hardlinks_(void (*cleanup) (void), const char *dir)
+{
+ unsigned int i, j;
+ char base_filename[PATH_MAX], link_filename[PATH_MAX];
+ struct stat s;
+
+ if (stat(dir, &s) == -1 && errno == ENOENT)
+ SAFE_MKDIR(cleanup, dir, 0744);
+
+ SAFE_STAT(cleanup, dir, &s);
+ if (!S_ISDIR(s.st_mode)) {
+ tst_brkm(TBROK, cleanup, "%s is not directory", dir);
+ return 0;
+ }
+
+ sprintf(base_filename, "%s/testfile0", dir);
+ SAFE_TOUCH(cleanup, base_filename, 0644, NULL);
+
+ for (i = 1; i < MAX_SANE_HARD_LINKS; i++) {
+ sprintf(link_filename, "%s/testfile%d", dir, i);
+
+ if (link(base_filename, link_filename) == 0)
+ continue;
+
+ switch (errno) {
+ case EMLINK:
+ SAFE_STAT(cleanup, base_filename, &s);
+ if (s.st_nlink != i) {
+ tst_brkm(TBROK, cleanup, "wrong number of "
+ "hard links for %s have %i, should be"
+ " %d", base_filename,
+ (int)s.st_nlink, i);
+ return 0;
+ } else {
+ tst_resm(TINFO, "the maximum number of hard "
+ "links to %s is hit: %d",
+ base_filename, (int)s.st_nlink);
+ return s.st_nlink;
+ }
+ case ENOSPC:
+ case EDQUOT:
+ tst_resm(TINFO | TERRNO, "link(%s, %s) failed",
+ base_filename, link_filename);
+ goto max_hardlinks_cleanup;
+ default:
+ tst_brkm(TBROK, cleanup, "link(%s, %s) failed "
+ "unexpectedly: %s", base_filename,
+ link_filename, strerror(errno));
+ return 0;
+ }
+ }
+
+ tst_resm(TINFO, "Failed reach the hardlinks limit");
+
+max_hardlinks_cleanup:
+ for (j = 0; j < i; j++) {
+ sprintf(link_filename, "%s/testfile%d", dir, j);
+ SAFE_UNLINK(cleanup, link_filename);
+ }
+
+ return 0;
+}
+
+int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir)
+{
+ unsigned int i, j, whitelist_size;
+ char dirname[PATH_MAX];
+ struct stat s;
+ long fs_type;
+
+ if (stat(dir, &s) == -1 && errno == ENOENT)
+ SAFE_MKDIR(cleanup, dir, 0744);
+
+ SAFE_STAT(cleanup, dir, &s);
+ if (!S_ISDIR(s.st_mode)) {
+ tst_brkm(TBROK, cleanup, "%s is not directory", dir);
+ return 0;
+ }
+
+ /* for current kernel, subdir limit is not availiable for all fs */
+ fs_type = tst_fs_type(cleanup, dir);
+
+ whitelist_size = ARRAY_SIZE(subdir_limit_whitelist);
+ for (i = 0; i < whitelist_size; i++) {
+ if (fs_type == subdir_limit_whitelist[i])
+ break;
+ }
+ if (i == whitelist_size) {
+ tst_resm(TINFO, "subdir limit is not availiable for "
+ "%s filesystem", tst_fs_type_name(fs_type));
+ return 0;
+ }
+
+ for (i = 0; i < MAX_SANE_HARD_LINKS; i++) {
+ sprintf(dirname, "%s/testdir%d", dir, i);
+
+ if (mkdir(dirname, 0755) == 0)
+ continue;
+
+ switch (errno) {
+ case EMLINK:
+ SAFE_STAT(cleanup, dir, &s);
+ /*
+ * i+2 because there are two links to each newly
+ * created directory (the '.' and link from parent dir)
+ */
+ if (s.st_nlink != (i + 2)) {
+ tst_brkm(TBROK, cleanup, "%s link counts have"
+ "%d, should be %d", dir,
+ (int)s.st_nlink, i + 2);
+ return 0;
+ } else {
+ tst_resm(TINFO, "the maximum subdirectories in "
+ "%s is hit: %d", dir, (int)s.st_nlink);
+ return s.st_nlink;
+ }
+ case ENOSPC:
+ case EDQUOT:
+ tst_resm(TINFO | TERRNO, "mkdir(%s, 0755) failed",
+ dirname);
+ goto max_subdirs_cleanup;
+ default:
+ tst_brkm(TBROK, cleanup, "mkdir(%s, 0755) failed "
+ "unexpectedly: %s", dirname,
+ strerror(errno));
+ return 0;
+ }
+
+ }
+
+ tst_resm(TINFO, "Failed reach the subdirs limit on %s filesystem",
+ tst_fs_type_name(fs_type));
+
+max_subdirs_cleanup:
+ for (j = 0; j < i; j++) {
+ sprintf(dirname, "%s/testdir%d", dir, j);
+ SAFE_RMDIR(cleanup, dirname);
+ }
+
+ return 0;
+}
diff --git a/src/kernel/tests/lib/tst_fs_setup.c b/src/kernel/tests/lib/tst_fs_setup.c
new file mode 100644
index 0000000..54ea370
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fs_setup.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/mount.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_fs.h"
+
+#define TST_FS_SETUP_OVERLAYFS_MSG "overlayfs is not configured in this kernel"
+#define TST_FS_SETUP_OVERLAYFS_CONFIG "lowerdir="OVL_LOWER",upperdir="OVL_UPPER",workdir="OVL_WORK
+
+void create_overlay_dirs(void)
+{
+ DIR *dir = opendir(OVL_LOWER);
+ if (dir == NULL) {
+ SAFE_MKDIR(OVL_LOWER, 0755);
+ SAFE_MKDIR(OVL_UPPER, 0755);
+ SAFE_MKDIR(OVL_WORK, 0755);
+ SAFE_MKDIR(OVL_MNT, 0755);
+ return;
+ }
+ closedir(dir);
+}
+
+int mount_overlay(const char *file, const int lineno, int skip)
+{
+ int ret;
+
+ create_overlay_dirs();
+ ret = mount("overlay", OVL_MNT, "overlay", 0,
+ TST_FS_SETUP_OVERLAYFS_CONFIG);
+ if (ret == 0)
+ return 0;
+
+ if (errno == ENODEV) {
+ if (skip) {
+ tst_brk(TCONF, "%s:%d: " TST_FS_SETUP_OVERLAYFS_MSG,
+ file, lineno);
+ } else {
+ tst_res(TINFO, "%s:%d: " TST_FS_SETUP_OVERLAYFS_MSG,
+ file, lineno);
+ }
+ } else {
+ tst_brk(TBROK | TERRNO, "overlayfs mount failed");
+ }
+ return ret;
+}
diff --git a/src/kernel/tests/lib/tst_fs_type.c b/src/kernel/tests/lib/tst_fs_type.c
new file mode 100644
index 0000000..1d0ac96
--- /dev/null
+++ b/src/kernel/tests/lib/tst_fs_type.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2014 Linux Test Project
+ *
+ * Cyril Hrubis <chrubis@suse.cz> 2014
+ * Michal Simek <monstr@monstr.eu> 2009
+ * Kumar Gala <galak@kernel.crashing.org> 2007
+ * Ricky Ng-Adam <rngadam@yahoo.com> 2005
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <sys/vfs.h>
+#include "test.h"
+#include "tst_fs.h"
+
+long tst_fs_type_(void (*cleanup)(void), const char *path)
+{
+ struct statfs sbuf;
+
+ if (statfs(path, &sbuf)) {
+ tst_brkm(TBROK | TERRNO, cleanup,
+ "tst_fs_type: Failed to statfs(%s)", path);
+ return 0;
+ }
+
+ return sbuf.f_type;
+}
+
+const char *tst_fs_type_name(long f_type)
+{
+ switch (f_type) {
+ case TST_TMPFS_MAGIC:
+ return "TMPFS";
+ case TST_NFS_MAGIC:
+ return "NFS";
+ case TST_V9FS_MAGIC:
+ return "9P";
+ case TST_RAMFS_MAGIC:
+ return "RAMFS";
+ case TST_BTRFS_MAGIC:
+ return "BTRFS";
+ case TST_XFS_MAGIC:
+ return "XFS";
+ case TST_EXT2_OLD_MAGIC:
+ return "EXT2";
+ case TST_EXT234_MAGIC:
+ return "EXT2/EXT3/EXT4";
+ case TST_MINIX_MAGIC:
+ case TST_MINIX_MAGIC2:
+ case TST_MINIX2_MAGIC:
+ case TST_MINIX2_MAGIC2:
+ case TST_MINIX3_MAGIC:
+ return "MINIX";
+ case TST_UDF_MAGIC:
+ return "UDF";
+ case TST_SYSV2_MAGIC:
+ case TST_SYSV4_MAGIC:
+ return "SYSV";
+ case TST_UFS_MAGIC:
+ case TST_UFS2_MAGIC:
+ return "UFS";
+ case TST_F2FS_MAGIC:
+ return "F2FS";
+ case TST_NILFS_MAGIC:
+ return "NILFS";
+ case TST_EXOFS_MAGIC:
+ return "EXOFS";
+ case TST_OVERLAYFS_MAGIC:
+ return "OVERLAYFS";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/src/kernel/tests/lib/tst_get_bad_addr.c b/src/kernel/tests/lib/tst_get_bad_addr.c
new file mode 100644
index 0000000..098e72b
--- /dev/null
+++ b/src/kernel/tests/lib/tst_get_bad_addr.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/mman.h>
+#include "test.h"
+#include "tst_get_bad_addr.h"
+
+void *tst_get_bad_addr(void (*cleanup_fn) (void))
+{
+ void *bad_addr;
+
+ bad_addr = mmap(0, 1, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ if (bad_addr == MAP_FAILED)
+ tst_brkm(TBROK, cleanup_fn, "mmap() failed to get bad address");
+
+ return bad_addr;
+}
diff --git a/src/kernel/tests/lib/tst_hugepage.c b/src/kernel/tests/lib/tst_hugepage.c
new file mode 100644
index 0000000..1d0e62e
--- /dev/null
+++ b/src/kernel/tests/lib/tst_hugepage.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ */
+
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+#include "tst_hugepage.h"
+
+unsigned long tst_hugepages;
+char *nr_opt;
+char *Hopt;
+
+size_t tst_get_hugepage_size(void)
+{
+ if (access(PATH_HUGEPAGES, F_OK))
+ return 0;
+
+ return SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
+}
+
+unsigned long tst_request_hugepages(unsigned long hpages)
+{
+ unsigned long val, max_hpages;
+
+ if (access(PATH_HUGEPAGES, F_OK)) {
+ tst_hugepages = 0;
+ goto out;
+ }
+
+ if (nr_opt)
+ tst_hugepages = SAFE_STRTOL(nr_opt, 1, LONG_MAX);
+ else
+ tst_hugepages = hpages;
+
+ SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3");
+ max_hpages = SAFE_READ_MEMINFO("MemFree:") / SAFE_READ_MEMINFO("Hugepagesize:");
+
+ if (tst_hugepages > max_hpages) {
+ tst_res(TINFO, "Requested number(%lu) of hugepages is too large, "
+ "limiting to 80%% of the max hugepage count %lu",
+ tst_hugepages, max_hpages);
+ tst_hugepages = max_hpages * 0.8;
+
+ if (tst_hugepages < 1)
+ goto out;
+ }
+
+ tst_sys_conf_save("?/proc/sys/vm/nr_hugepages");
+ SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", tst_hugepages);
+ SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val);
+ if (val != tst_hugepages)
+ tst_brk(TCONF, "nr_hugepages = %lu, but expect %lu. "
+ "Not enough hugepages for testing.",
+ val, tst_hugepages);
+
+ tst_res(TINFO, "%lu hugepage(s) reserved", tst_hugepages);
+out:
+ return tst_hugepages;
+}
diff --git a/src/kernel/tests/lib/tst_ioctl.c b/src/kernel/tests/lib/tst_ioctl.c
new file mode 100644
index 0000000..364220b
--- /dev/null
+++ b/src/kernel/tests/lib/tst_ioctl.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+
+int tst_fibmap(const char *filename)
+{
+ /* test if FIBMAP ioctl is supported */
+ int fd, block = 0;
+
+ fd = open(filename, O_RDWR | O_CREAT, 0666);
+ if (fd < 0) {
+ tst_res(TWARN | TERRNO,
+ "open(%s, O_RDWR | O_CREAT, 0666) failed", filename);
+ return -1;
+ }
+
+ if (ioctl(fd, FIBMAP, &block)) {
+ tst_res(TINFO | TERRNO, "FIBMAP ioctl is NOT supported");
+ close(fd);
+ return 1;
+ }
+ tst_res(TINFO, "FIBMAP ioctl is supported");
+
+ if (close(fd)) {
+ tst_res(TWARN | TERRNO, "close(fd) failed");
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/kernel/tests/lib/tst_kconfig.c b/src/kernel/tests/lib/tst_kconfig.c
new file mode 100644
index 0000000..d49187b
--- /dev/null
+++ b/src/kernel/tests/lib/tst_kconfig.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/utsname.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_kconfig.h"
+
+static const char *kconfig_path(char *path_buf, size_t path_buf_len)
+{
+ const char *path = getenv("KCONFIG_PATH");
+ struct utsname un;
+
+ if (path) {
+ if (!access(path, F_OK))
+ return path;
+
+ tst_res(TWARN, "KCONFIG_PATH='%s' does not exist", path);
+ }
+
+ if (!access("/proc/config.gz", F_OK))
+ return "/proc/config.gz";
+
+ uname(&un);
+
+ /* Debian and derivatives */
+ snprintf(path_buf, path_buf_len, "/boot/config-%s", un.release);
+
+ if (!access(path_buf, F_OK))
+ return path_buf;
+
+ /* Clear Linux */
+ snprintf(path_buf, path_buf_len, "/lib/kernel/config-%s", un.release);
+
+ if (!access(path_buf, F_OK))
+ return path_buf;
+
+ tst_res(TINFO, "Couldn't locate kernel config!");
+
+ return NULL;
+}
+
+static char is_gzip;
+
+static FILE *open_kconfig(void)
+{
+ FILE *fp;
+ char buf[1064];
+ char path_buf[1024];
+ const char *path = kconfig_path(path_buf, sizeof(path_buf));
+
+ if (!path)
+ return NULL;
+
+ tst_res(TINFO, "Parsing kernel config '%s'", path);
+
+ is_gzip = !!strstr(path, ".gz");
+
+ if (is_gzip) {
+ snprintf(buf, sizeof(buf), "zcat '%s'", path);
+ fp = popen(buf, "r");
+ } else {
+ fp = fopen(path, "r");
+ }
+
+ if (!fp)
+ tst_brk(TBROK | TERRNO, "Failed to open '%s'", path);
+
+ return fp;
+}
+
+static void close_kconfig(FILE *fp)
+{
+ if (is_gzip)
+ pclose(fp);
+ else
+ fclose(fp);
+}
+
+struct match {
+ /* match len, string length up to \0 or = */
+ size_t len;
+ /* if set part of conf string after = */
+ const char *val;
+ /* if set the config option was matched already */
+ int match;
+};
+
+static int is_set(const char *str, const char *val)
+{
+ size_t vlen = strlen(val);
+
+ while (isspace(*str))
+ str++;
+
+ if (strncmp(str, val, vlen))
+ return 0;
+
+ switch (str[vlen]) {
+ case ' ':
+ case '\n':
+ case '\0':
+ return 1;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static inline int match(struct match *match, const char *conf,
+ struct tst_kconfig_res *result, const char *line)
+{
+ if (match->match)
+ return 0;
+
+ const char *cfg = strstr(line, "CONFIG_");
+
+ if (!cfg)
+ return 0;
+
+ if (strncmp(cfg, conf, match->len))
+ return 0;
+
+ const char *val = &cfg[match->len];
+
+ switch (cfg[match->len]) {
+ case '=':
+ break;
+ case ' ':
+ if (is_set(val, "is not set")) {
+ result->match = 'n';
+ goto match;
+ }
+ /* fall through */
+ default:
+ return 0;
+ }
+
+ if (is_set(val, "=y")) {
+ result->match = 'y';
+ goto match;
+ }
+
+ if (is_set(val, "=m")) {
+ result->match = 'm';
+ goto match;
+ }
+
+ result->match = 'v';
+ result->value = strndup(val+1, strlen(val)-2);
+
+match:
+ match->match = 1;
+ return 1;
+}
+
+void tst_kconfig_read(const char *const *kconfigs,
+ struct tst_kconfig_res results[], size_t cnt)
+{
+ struct match matches[cnt];
+ FILE *fp;
+ unsigned int i, j;
+ char buf[1024];
+
+ for (i = 0; i < cnt; i++) {
+ const char *val = strchr(kconfigs[i], '=');
+
+ if (strncmp("CONFIG_", kconfigs[i], 7))
+ tst_brk(TBROK, "Invalid config string '%s'", kconfigs[i]);
+
+ matches[i].match = 0;
+ matches[i].len = strlen(kconfigs[i]);
+
+ if (val) {
+ matches[i].val = val + 1;
+ matches[i].len -= strlen(val);
+ }
+
+ results[i].match = 0;
+ results[i].value = NULL;
+ }
+
+ fp = open_kconfig();
+ if (!fp)
+ tst_brk(TBROK, "Cannot parse kernel .config");
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ for (i = 0; i < cnt; i++) {
+ if (match(&matches[i], kconfigs[i], &results[i], buf)) {
+ for (j = 0; j < cnt; j++) {
+ if (matches[j].match)
+ break;
+ }
+
+ if (j == cnt)
+ goto exit;
+ }
+ }
+
+ }
+
+exit:
+ close_kconfig(fp);
+}
+
+static size_t array_len(const char *const kconfigs[])
+{
+ size_t i = 0;
+
+ while (kconfigs[++i]);
+
+ return i;
+}
+
+static int compare_res(struct tst_kconfig_res *res, const char *kconfig,
+ char match, const char *val)
+{
+ if (res->match != match) {
+ tst_res(TINFO, "Needs kernel %s, have %c", kconfig, res->match);
+ return 1;
+ }
+
+ if (match != 'v')
+ return 0;
+
+ if (strcmp(res->value, val)) {
+ tst_res(TINFO, "Needs kernel %s, have %s", kconfig, res->value);
+ return 1;
+ }
+
+ return 0;
+}
+
+void tst_kconfig_check(const char *const kconfigs[])
+{
+ size_t cnt = array_len(kconfigs);
+ struct tst_kconfig_res results[cnt];
+ unsigned int i;
+ int abort_test = 0;
+
+ tst_kconfig_read(kconfigs, results, cnt);
+
+ for (i = 0; i < cnt; i++) {
+ if (results[i].match == 0) {
+ tst_res(TINFO, "Missing kernel %s", kconfigs[i]);
+ abort_test = 1;
+ continue;
+ }
+
+ if (results[i].match == 'n') {
+ tst_res(TINFO, "Kernel %s is not set", kconfigs[i]);
+ abort_test = 1;
+ continue;
+ }
+
+ const char *val = strchr(kconfigs[i], '=');
+
+ if (val) {
+ char match = 'v';
+ val++;
+
+ if (!strcmp(val, "y"))
+ match = 'y';
+
+ if (!strcmp(val, "m"))
+ match = 'm';
+
+ if (compare_res(&results[i], kconfigs[i], match, val))
+ abort_test = 1;
+
+ }
+
+ free(results[i].value);
+ }
+
+ if (abort_test)
+ tst_brk(TCONF, "Aborting due to unsuitable kernel config, see above!");
+}
diff --git a/src/kernel/tests/lib/tst_kernel.c b/src/kernel/tests/lib/tst_kernel.c
new file mode 100644
index 0000000..57fa4b2
--- /dev/null
+++ b/src/kernel/tests/lib/tst_kernel.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#include "test.h"
+#include "tst_kernel.h"
+
+static int get_kernel_bits_from_uname(struct utsname *buf)
+{
+ if (uname(buf)) {
+ tst_brkm(TBROK | TERRNO, NULL, "uname()");
+ return -1;
+ }
+
+ return strstr(buf->machine, "64") ? 64 : 32;
+}
+
+int tst_kernel_bits(void)
+{
+ struct utsname buf;
+ int kernel_bits = get_kernel_bits_from_uname(&buf);
+
+ if (kernel_bits == -1)
+ return -1;
+
+ /*
+ * ARM64 (aarch64) defines 32-bit compatibility modes as
+ * armv8l and armv8b (little and big endian).
+ * s390x is 64bit but not contain 64 in the words.
+ */
+ if (!strcmp(buf.machine, "armv8l") || !strcmp(buf.machine, "armv8b")
+ || !strcmp(buf.machine, "s390x"))
+ kernel_bits = 64;
+
+#ifdef __ANDROID__
+ /* Android's bionic libc sets the PER_LINUX32 personality for all 32-bit
+ * programs. This will cause buf.machine to report as i686 even though
+ * the kernel itself is 64-bit.
+ */
+ if (!strcmp(buf.machine, "i686") &&
+ (personality(0xffffffff) & PER_MASK) == PER_LINUX32) {
+ /* Set the personality back to the default. */
+ if (personality(PER_LINUX) == -1) {
+ tst_brkm(TBROK | TERRNO, NULL, "personality()");
+ return -1;
+ }
+
+ /* Redo the uname check without the PER_LINUX32 personality to
+ * determine the actual kernel bits value.
+ */
+ kernel_bits = get_kernel_bits_from_uname(&buf);
+ if (kernel_bits == -1)
+ return -1;
+
+ /* Set the personality back to PER_LINUX32. */
+ if (personality(PER_LINUX32) == -1) {
+ tst_brkm(TBROK | TERRNO, NULL, "personality()");
+ return -1;
+ }
+ }
+#endif /* __ANDROID__ */
+
+ tst_resm(TINFO, "uname.machine=%s kernel is %ibit",
+ buf.machine, kernel_bits);
+
+ return kernel_bits;
+}
+
+int tst_check_driver(const char *name)
+{
+#ifndef __ANDROID__
+ const char * const argv[] = { "modprobe", "-n", name, NULL };
+ int res = tst_cmd_(NULL, argv, "/dev/null", "/dev/null",
+ TST_CMD_PASS_RETVAL);
+
+ /* 255 - it looks like modprobe not available */
+ return (res == 255) ? 0 : res;
+#else
+ /* Android modprobe may not have '-n', or properly installed
+ * module.*.bin files to determine built-in drivers. Assume
+ * all drivers are available.
+ */
+ return 0;
+#endif
+}
diff --git a/src/kernel/tests/lib/tst_kvercmp.c b/src/kernel/tests/lib/tst_kvercmp.c
new file mode 100644
index 0000000..5d56e30
--- /dev/null
+++ b/src/kernel/tests/lib/tst_kvercmp.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2003
+ * AUTHOR: Paul Larson <plars@linuxtestproject.org>
+ * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/utsname.h>
+#include "test.h"
+
+#define OSRELEASE_PATH "/etc/os-release"
+
+static char *parse_digit(const char *str, int *d)
+{
+ unsigned long v;
+ char *end;
+
+ v = strtoul(str, &end, 10);
+ if (str == end)
+ return NULL;
+
+ if (v > INT_MAX)
+ return NULL;
+
+ *d = v;
+
+ return end;
+}
+
+int tst_parse_kver(const char *str_kver, int *v1, int *v2, int *v3)
+{
+ const char *str = str_kver;
+
+ *v1 = 0;
+ *v2 = 0;
+ *v3 = 0;
+
+ if (!(str = parse_digit(str, v1)))
+ return 1;
+
+ if (*(str++) != '.')
+ return 1;
+
+ if (!(str = parse_digit(str, v2)))
+ return 1;
+
+ /*
+ * Check for a short version e.g '2.4'
+ */
+ if (*str == ' ' || *str == '\0')
+ return 0;
+
+ if (*(str++) != '.')
+ return 1;
+
+ /*
+ * Ignore rest of the string in order not to break on versions as
+ * 4.8.1-52-default.
+ */
+ if (!parse_digit(str, v3))
+ return 1;
+
+ return 0;
+}
+
+int tst_kvcmp(const char *cur_kver, int r1, int r2, int r3)
+{
+ int a1, a2, a3;
+ int testver, currver;
+
+ if (tst_parse_kver(cur_kver, &a1, &a2, &a3)) {
+ tst_resm(TWARN,
+ "Invalid kernel version %s, expected %%d.%%d.%%d",
+ cur_kver);
+ }
+
+ testver = (r1 << 16) + (r2 << 8) + r3;
+ currver = (a1 << 16) + (a2 << 8) + a3;
+
+ return currver - testver;
+}
+
+int tst_kvercmp(int r1, int r2, int r3)
+{
+ struct utsname uval;
+
+ uname(&uval);
+
+ return tst_kvcmp(uval.release, r1, r2, r3);
+}
+
+int tst_kvexcmp(const char *tst_exv, const char *cur_ver)
+{
+ int c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0;
+ int t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0;
+ int ret;
+
+ sscanf(cur_ver, "%d.%d.%d-%d.%d", &c1, &c2, &c3, &c4, &c5);
+ sscanf(tst_exv, "%d.%d.%d-%d.%d", &t1, &t2, &t3, &t4, &t5);
+
+ if ((ret = c1 - t1))
+ return ret;
+ if ((ret = c2 - t2))
+ return ret;
+ if ((ret = c3 - t3))
+ return ret;
+ if ((ret = c4 - t4))
+ return ret;
+
+ return c5 - t5;
+}
+
+const char *tst_kvcmp_distname(const char *kver)
+{
+ static char distname[64];
+ char *ret = distname;
+ char *p = distname;
+
+ if (strstr(kver, ".el5uek"))
+ return "OL5UEK";
+
+ if (strstr(kver, ".el5"))
+ return "RHEL5";
+
+ if (strstr(kver, ".el6uek"))
+ return "OL6UEK";
+
+ if (strstr(kver, ".el6"))
+ return "RHEL6";
+
+ if (access(OSRELEASE_PATH, F_OK) != -1) {
+ SAFE_FILE_LINES_SCANF(NULL, OSRELEASE_PATH, "ID=%s", distname);
+
+ if (p[0] == '"') {
+ ret = distname + 1;
+ p = ret;
+ }
+
+ while (*p) {
+ if (*p == '"') {
+ *p = 0;
+ break;
+ }
+ *p = toupper((unsigned char)*p);
+ p++;
+ }
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers)
+{
+ int i;
+ const char *kver;
+ struct utsname uval;
+ const char *cur_dist_name;
+
+ uname(&uval);
+ kver = uval.release;
+ cur_dist_name = tst_kvcmp_distname(kver);
+
+ if (cur_dist_name == NULL)
+ return tst_kvercmp(r1, r2, r3);
+
+ for (i = 0; vers[i].dist_name; i++) {
+ if (!strcmp(vers[i].dist_name, cur_dist_name)) {
+ tst_resm(TINFO, "Detected %s using kernel version %s",
+ cur_dist_name, kver);
+ return tst_kvexcmp(vers[i].extra_ver, kver);
+ }
+ }
+
+ return tst_kvcmp(kver, r1, r2, r3);
+}
diff --git a/src/kernel/tests/lib/tst_lockdown.c b/src/kernel/tests/lib/tst_lockdown.c
new file mode 100644
index 0000000..e7c1981
--- /dev/null
+++ b/src/kernel/tests/lib/tst_lockdown.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#define TST_NO_DEFAULT_MAIN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+
+#include "tst_test.h"
+#include "tst_safe_macros.h"
+#include "tst_safe_stdio.h"
+#include "tst_lockdown.h"
+
+int tst_lockdown_enabled(void)
+{
+ char line[BUFSIZ];
+ FILE *file;
+
+ if (access(PATH_LOCKDOWN, F_OK) != 0) {
+ tst_res(TINFO, "Unable to determine system lockdown state");
+ return 0;
+ }
+
+ file = SAFE_FOPEN(PATH_LOCKDOWN, "r");
+ if (!fgets(line, sizeof(line), file))
+ tst_brk(TBROK | TERRNO, "fgets %s", PATH_LOCKDOWN);
+ SAFE_FCLOSE(file);
+
+ return (strstr(line, "[none]") == NULL);
+}
diff --git a/src/kernel/tests/lib/tst_memutils.c b/src/kernel/tests/lib/tst_memutils.c
new file mode 100644
index 0000000..f134d90
--- /dev/null
+++ b/src/kernel/tests/lib/tst_memutils.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
+ */
+
+#include <unistd.h>
+#include <limits.h>
+#include <sys/sysinfo.h>
+#include <stdlib.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+#define BLOCKSIZE (16 * 1024 * 1024)
+
+void tst_pollute_memory(size_t maxsize, int fillchar)
+{
+ size_t i, map_count = 0, safety = 0, blocksize = BLOCKSIZE;
+ void **map_blocks;
+ struct sysinfo info;
+
+ SAFE_SYSINFO(&info);
+ safety = 4096 * SAFE_SYSCONF(_SC_PAGESIZE) / info.mem_unit;
+
+ if (info.freeswap > safety)
+ safety = 0;
+
+ /* Not enough free memory to avoid invoking OOM killer */
+ if (info.freeram <= safety)
+ return;
+
+ if (!maxsize)
+ maxsize = SIZE_MAX;
+
+ if (info.freeram - safety < maxsize / info.mem_unit)
+ maxsize = (info.freeram - safety) * info.mem_unit;
+
+ blocksize = MIN(maxsize, blocksize);
+ map_count = maxsize / blocksize;
+ map_blocks = SAFE_MALLOC(map_count * sizeof(void *));
+
+ /*
+ * Keep allocating until the first failure. The address space may be
+ * too fragmented or just smaller than maxsize.
+ */
+ for (i = 0; i < map_count; i++) {
+ map_blocks[i] = mmap(NULL, blocksize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ if (map_blocks[i] == MAP_FAILED) {
+ map_count = i;
+ break;
+ }
+
+ memset(map_blocks[i], fillchar, blocksize);
+ }
+
+ for (i = 0; i < map_count; i++)
+ SAFE_MUNMAP(map_blocks[i], blocksize);
+
+ free(map_blocks);
+}
diff --git a/src/kernel/tests/lib/tst_mkfs.c b/src/kernel/tests/lib/tst_mkfs.c
new file mode 100644
index 0000000..38b2e71
--- /dev/null
+++ b/src/kernel/tests/lib/tst_mkfs.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "test.h"
+#include "ltp_priv.h"
+#include "tst_mkfs.h"
+#include "tst_device.h"
+
+#define OPTS_MAX 32
+
+void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void),
+ const char *dev, const char *fs_type,
+ const char *const fs_opts[], const char *const extra_opts[])
+{
+ int i, pos = 1, ret;
+ char mkfs[64];
+ const char *argv[OPTS_MAX] = {mkfs};
+ char fs_opts_str[1024] = "";
+ char extra_opts_str[1024] = "";
+
+ if (!dev) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: No device specified", file, lineno);
+ return;
+ }
+
+ if (!fs_type) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: No fs_type specified", file, lineno);
+ return;
+ }
+
+ snprintf(mkfs, sizeof(mkfs), "mkfs.%s", fs_type);
+
+ if (fs_opts) {
+ for (i = 0; fs_opts[i]; i++) {
+ argv[pos++] = fs_opts[i];
+
+ if (pos + 2 > OPTS_MAX) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: Too much mkfs options",
+ file, lineno);
+ return;
+ }
+
+ if (i)
+ strcat(fs_opts_str, " ");
+ strcat(fs_opts_str, fs_opts[i]);
+ }
+ }
+
+ argv[pos++] = dev;
+
+ if (extra_opts) {
+ for (i = 0; extra_opts[i]; i++) {
+ argv[pos++] = extra_opts[i];
+
+ if (pos + 1 > OPTS_MAX) {
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: Too much mkfs options", file, lineno);
+ return;
+ }
+
+ if (i)
+ strcat(extra_opts_str, " ");
+ strcat(extra_opts_str, extra_opts[i]);
+ }
+ }
+
+ argv[pos] = NULL;
+
+ if (tst_clear_device(dev))
+ tst_brkm(TBROK, cleanup_fn, "tst_clear_device() failed");
+
+ tst_resm(TINFO, "Formatting %s with %s opts='%s' extra opts='%s'",
+ dev, fs_type, fs_opts_str, extra_opts_str);
+ ret = tst_cmd(cleanup_fn, argv, "/dev/null", NULL, TST_CMD_PASS_RETVAL |
+ TST_CMD_TCONF_ON_MISSING);
+
+ switch (ret) {
+ case 0:
+ break;
+ case 255:
+ tst_brkm(TCONF, cleanup_fn,
+ "%s:%d: %s not found in $PATH", file, lineno, mkfs);
+ break;
+ default:
+ tst_brkm(TBROK, cleanup_fn,
+ "%s:%d: %s failed with %i", file, lineno, mkfs, ret);
+ }
+}
+
+const char *tst_dev_fs_type(void)
+{
+ const char *fs_type;
+
+ fs_type = getenv("LTP_DEV_FS_TYPE");
+
+ if (fs_type)
+ return fs_type;
+
+ return DEFAULT_FS_TYPE;
+}
diff --git a/src/kernel/tests/lib/tst_module.c b/src/kernel/tests/lib/tst_module.c
new file mode 100644
index 0000000..eda6187
--- /dev/null
+++ b/src/kernel/tests/lib/tst_module.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "test.h"
+#include "ltp_priv.h"
+#include "old_module.h"
+
+void tst_module_exists(void (cleanup_fn)(void),
+ const char *mod_name, char **mod_path)
+{
+ /* check current working directory */
+ if (access(mod_name, F_OK) == 0) {
+ if (mod_path != NULL)
+ *mod_path = strdup(mod_name);
+ return;
+ }
+ char *buf = NULL;
+ int err = -1;
+ /* check LTP installation path */
+ const char *ltproot = getenv("LTPROOT");
+ if (ltproot != NULL) {
+ if (asprintf(&buf, "%s/testcases/bin/%s",
+ ltproot, mod_name) == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "asprintf failed at %s:%d",
+ __FILE__, __LINE__);
+ return;
+ }
+ err = access(buf, F_OK);
+ }
+ /* check start working directory */
+ if (err == -1 && tst_tmpdir_created()) {
+ free(buf);
+ if (asprintf(&buf, "%s/%s", tst_get_startwd(),
+ mod_name) == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "asprintf failed at %s:%d",
+ __FILE__, __LINE__);
+ return;
+ }
+ err = access(buf, F_OK);
+ }
+
+ if (err != 0) {
+ free(buf);
+ tst_brkm(TCONF, cleanup_fn, "Failed to find module '%s'",
+ mod_name);
+ return;
+ }
+
+ if (mod_path != NULL)
+ *mod_path = buf;
+ else
+ free(buf);
+}
+
+void tst_module_load(void (cleanup_fn)(void),
+ const char *mod_name, char *const argv[])
+{
+ char *mod_path = NULL;
+ tst_module_exists(cleanup_fn, mod_name, &mod_path);
+
+ const int offset = 2; /* command name & module path */
+ int size = 0;
+ while (argv && argv[size])
+ ++size;
+ size += offset;
+ const char *mod_argv[size + 1]; /* + NULL in the end */
+ mod_argv[size] = NULL;
+ mod_argv[0] = "insmod";
+ mod_argv[1] = mod_path;
+
+ int i;
+ for (i = offset; i < size; ++i)
+ mod_argv[i] = argv[i - offset];
+
+ tst_cmd(cleanup_fn, mod_argv, NULL, NULL, 0);
+ free(mod_path);
+}
+
+void tst_module_unload(void (cleanup_fn)(void), const char *mod_name)
+{
+ int i, rc;
+
+ const char *const argv[] = { "rmmod", mod_name, NULL };
+
+ rc = 1;
+ for (i = 0; i < 50; i++) {
+ rc = tst_cmd(NULL, argv, "/dev/null", "/dev/null",
+ TST_CMD_PASS_RETVAL);
+ if (!rc)
+ break;
+
+ usleep(20000);
+ }
+
+ if (rc) {
+ tst_brkm(TBROK, cleanup_fn,
+ "could not unload %s module", mod_name);
+ }
+}
diff --git a/src/kernel/tests/lib/tst_net.c b/src/kernel/tests/lib/tst_net.c
new file mode 100644
index 0000000..8a589b0
--- /dev/null
+++ b/src/kernel/tests/lib/tst_net.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2019 Petr Vorel <pvorel@suse.cz>
+ * Copyright (c) 2019 Martin Doucha <mdoucha@suse.cz>
+ */
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_net.h"
+#include "tst_private.h"
+
+void tst_print_svar(const char *name, const char *val)
+{
+ if (name && val)
+ printf("export %s=\"%s\"\n", name, val);
+}
+
+void tst_print_svar_change(const char *name, const char *val)
+{
+ if (name && val)
+ printf("export %s=\"${%s:-%s}\"\n", name, name, val);
+}
+
+/*
+ * Function bit_count is from ipcalc project, ipcalc.c.
+ */
+static int tst_bit_count(uint32_t i)
+{
+ int c = 0;
+ unsigned int seen_one = 0;
+
+ while (i > 0) {
+ if (i & 1) {
+ seen_one = 1;
+ c++;
+ } else {
+ if (seen_one)
+ return -1;
+ }
+ i >>= 1;
+ }
+
+ return c;
+}
+
+/*
+ * Function mask2prefix is from ipcalc project, ipcalc.c.
+ */
+static int tst_mask2prefix(struct in_addr mask)
+{
+ return tst_bit_count(ntohl(mask.s_addr));
+}
+
+/*
+ * Function ipv4_mask_to_int is from ipcalc project, ipcalc.c.
+ */
+static int tst_ipv4_mask_to_int(const char *prefix)
+{
+ int ret;
+ struct in_addr in;
+
+ ret = inet_pton(AF_INET, prefix, &in);
+ if (ret == 0)
+ return -1;
+
+ return tst_mask2prefix(in);
+}
+
+/*
+ * Function safe_atoi is from ipcalc project, ipcalc.c.
+ */
+static int tst_safe_atoi(const char *s, int *ret_i)
+{
+ char *x = NULL;
+ long l;
+
+ errno = 0;
+ l = strtol(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((long)(int)l != l)
+ return -ERANGE;
+
+ *ret_i = (int)l;
+
+ return 0;
+}
+
+/*
+ * Function get_prefix use code from ipcalc project, str_to_prefix/ipcalc.c.
+ */
+int tst_get_prefix(const char *ip_str, int is_ipv6)
+{
+ char *prefix_str = NULL;
+ int prefix = -1, r;
+
+ prefix_str = strchr(ip_str, '/');
+ if (!prefix_str)
+ return -1;
+
+ *(prefix_str++) = '\0';
+
+ if (!is_ipv6 && strchr(prefix_str, '.'))
+ prefix = tst_ipv4_mask_to_int(prefix_str);
+ else {
+ r = tst_safe_atoi(prefix_str, &prefix);
+ if (r != 0)
+ tst_brk_comment("conversion error: '%s' is not integer",
+ prefix_str);
+ }
+
+ if (prefix < 0 || ((is_ipv6 && prefix > MAX_IPV6_PREFIX) ||
+ (!is_ipv6 && prefix > MAX_IPV4_PREFIX)))
+ tst_brk_comment("bad %s prefix: %s", is_ipv6 ? "IPv6" : "IPv4",
+ prefix_str);
+
+ return prefix;
+}
+
+void tst_get_in_addr(const char *ip_str, struct in_addr *ip)
+{
+ if (inet_pton(AF_INET, ip_str, ip) <= 0)
+ tst_brk_comment("bad IPv4 address: '%s'", ip_str);
+}
+
+void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6)
+{
+ if (inet_pton(AF_INET6, ip_str, ip6) <= 0)
+ tst_brk_comment("bad IPv6 address: '%s'", ip_str);
+}
+
+socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr)
+{
+ struct sockaddr_in *inet_ptr;
+ struct sockaddr_in6 *inet6_ptr;
+ size_t tmp_size;
+ socklen_t ret = sizeof(*addr);
+
+ SAFE_GETSOCKNAME(sock, (struct sockaddr*)addr, &ret);
+
+ /* Sanitize wildcard addresses */
+ switch (addr->ss_family) {
+ case AF_INET:
+ inet_ptr = (struct sockaddr_in*)addr;
+
+ switch (ntohl(inet_ptr->sin_addr.s_addr)) {
+ case INADDR_ANY:
+ case INADDR_BROADCAST:
+ inet_ptr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ break;
+ }
+
+ break;
+
+ case AF_INET6:
+ inet6_ptr = (struct sockaddr_in6*)addr;
+ tmp_size = sizeof(struct in6_addr);
+
+ if (!memcmp(&inet6_ptr->sin6_addr, &in6addr_any, tmp_size)) {
+ memcpy(&inet6_ptr->sin6_addr, &in6addr_loopback,
+ tmp_size);
+ }
+
+ break;
+ }
+
+ return ret;
+}
+
+void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, uint16_t port)
+{
+ memset(sa, 0, sizeof(struct sockaddr_in));
+ sa->sin_family = AF_INET;
+ sa->sin_port = htons(port);
+ tst_get_in_addr(ip_str, &sa->sin_addr);
+}
+
+void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, uint16_t port)
+{
+ memset(sa, 0, sizeof(struct sockaddr_in));
+ sa->sin_family = AF_INET;
+ sa->sin_port = htons(port);
+ sa->sin_addr.s_addr = htonl(ip_val);
+}
+
+void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, uint16_t port)
+{
+ memset(sa, 0, sizeof(struct sockaddr_in6));
+ sa->sin6_family = AF_INET6;
+ sa->sin6_port = htons(port);
+ tst_get_in6_addr(ip_str, &sa->sin6_addr);
+}
+
+void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct in6_addr *ip_val, uint16_t port)
+{
+ memset(sa, 0, sizeof(struct sockaddr_in6));
+ sa->sin6_family = AF_INET6;
+ sa->sin6_port = htons(port);
+ memcpy(&sa->sin6_addr, ip_val, sizeof(struct in6_addr));
+}
+
+void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr,
+ const char *port, const struct addrinfo *hints,
+ struct addrinfo **addr_info)
+{
+ int err = getaddrinfo(src_addr, port, hints, addr_info);
+
+ if (err)
+ tst_brk(TBROK, "%s:%d: getaddrinfo failed, %s", file, lineno,
+ gai_strerror(err));
+
+ if (!*addr_info)
+ tst_brk(TBROK, "%s:%d: failed to get the address", file, lineno);
+}
diff --git a/src/kernel/tests/lib/tst_parse_opts.c b/src/kernel/tests/lib/tst_parse_opts.c
new file mode 100644
index 0000000..94970e1
--- /dev/null
+++ b/src/kernel/tests/lib/tst_parse_opts.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "test.h"
+#include "ltp_priv.h"
+
+void tst_parse_opts(int argc, char *argv[], const option_t *user_optarg,
+ void (*user_help)(void))
+{
+ const char *msg;
+
+ msg = parse_opts(argc, argv, user_optarg, user_help);
+
+ if (msg)
+ tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+}
diff --git a/src/kernel/tests/lib/tst_path_has_mnt_flags.c b/src/kernel/tests/lib/tst_path_has_mnt_flags.c
new file mode 100644
index 0000000..154bf41
--- /dev/null
+++ b/src/kernel/tests/lib/tst_path_has_mnt_flags.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 Fujitsu Ltd.
+ * Author: Xing Gu <gux.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <unistd.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <string.h>
+#include "test.h"
+
+/*
+ * Check whether a path is on a filesystem that is mounted with
+ * specified flags.
+ */
+int tst_path_has_mnt_flags_(void (cleanup_fn)(void),
+ const char *path, const char *flags[])
+{
+ struct mntent *mnt;
+ size_t prefix_max = 0, prefix_len;
+ int flags_matched = 0;
+ FILE *f;
+ int i;
+ char *tmpdir = NULL;
+
+ /*
+ * Default parameter is test temporary directory
+ */
+ if (path == NULL)
+ path = tmpdir = tst_get_tmpdir();
+
+ if (access(path, F_OK) == -1) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "tst_path_has_mnt_flags: path %s doesn't exist", path);
+ return -1;
+ }
+
+ f = setmntent("/proc/mounts", "r");
+ if (f == NULL) {
+ tst_brkm(TBROK | TERRNO, cleanup_fn,
+ "tst_path_has_mnt_flags: failed to open /proc/mounts");
+ return -1;
+ }
+
+ while ((mnt = getmntent(f))) {
+ /* ignore duplicit record for root fs */
+ if (!strcmp(mnt->mnt_fsname, "rootfs"))
+ continue;
+
+ prefix_len = strlen(mnt->mnt_dir);
+
+ if (strncmp(path, mnt->mnt_dir, prefix_len) == 0
+ && prefix_len > prefix_max) {
+ prefix_max = prefix_len;
+ flags_matched = 0;
+ i = 0;
+
+ while (flags[i] != NULL) {
+ if (hasmntopt(mnt, flags[i]) != NULL)
+ flags_matched++;
+ i++;
+ }
+ }
+ }
+
+ endmntent(f);
+
+ free(tmpdir);
+
+ return flags_matched;
+}
diff --git a/src/kernel/tests/lib/tst_pid.c b/src/kernel/tests/lib/tst_pid.c
new file mode 100644
index 0000000..9568cc9
--- /dev/null
+++ b/src/kernel/tests/lib/tst_pid.c
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright (c) International Business Machines Corp., 2009
+ * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "test.h"
+#include "tst_pid.h"
+#include "old_safe_file_ops.h"
+
+#define PID_MAX_PATH "/proc/sys/kernel/pid_max"
+
+pid_t tst_get_unused_pid_(void (*cleanup_fn) (void))
+{
+ pid_t pid;
+
+ SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &pid);
+
+ return pid;
+}
+
+int tst_get_free_pids_(void (*cleanup_fn) (void))
+{
+ FILE *f;
+ int rc, used_pids, max_pids;
+
+ f = popen("ps -eT | wc -l", "r");
+ if (!f) {
+ tst_resm(TBROK, "Could not run 'ps' to calculate used " "pids");
+ return -1;
+ }
+ rc = fscanf(f, "%i", &used_pids);
+ pclose(f);
+
+ if (rc != 1 || used_pids < 0) {
+ tst_resm(TBROK, "Could not read output of 'ps' to "
+ "calculate used pids");
+ return -1;
+ }
+
+ SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &max_pids);
+
+ /* max_pids contains the maximum PID + 1,
+ * used_pids contains used PIDs + 1,
+ * so this additional '1' is eliminated by the substraction */
+ return max_pids - used_pids;
+}
diff --git a/src/kernel/tests/lib/tst_process_state.c b/src/kernel/tests/lib/tst_process_state.c
new file mode 100644
index 0000000..11790c9
--- /dev/null
+++ b/src/kernel/tests/lib/tst_process_state.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012-2014 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "test.h"
+#include "tst_process_state.h"
+
+int tst_process_state_wait(const char *file, const int lineno,
+ void (*cleanup_fn)(void), pid_t pid,
+ const char state, unsigned int msec_timeout)
+{
+ char proc_path[128], cur_state;
+ unsigned int msecs = 0;
+
+ snprintf(proc_path, sizeof(proc_path), "/proc/%i/stat", pid);
+
+ for (;;) {
+ safe_file_scanf(file, lineno, cleanup_fn, proc_path,
+ "%*i %*s %c", &cur_state);
+
+ if (state == cur_state)
+ break;
+
+ usleep(1000);
+ msecs += 1;
+
+ if (msec_timeout && msecs >= msec_timeout) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int tst_process_state_wait2(pid_t pid, const char state)
+{
+ char proc_path[128], cur_state;
+
+ snprintf(proc_path, sizeof(proc_path), "/proc/%i/stat", pid);
+
+ for (;;) {
+ FILE *f = fopen(proc_path, "r");
+ if (!f) {
+ fprintf(stderr, "Failed to open '%s': %s\n",
+ proc_path, strerror(errno));
+ return 1;
+ }
+
+ if (fscanf(f, "%*i %*s %c", &cur_state) != 1) {
+ fclose(f);
+ fprintf(stderr, "Failed to read '%s': %s\n",
+ proc_path, strerror(errno));
+ return 1;
+ }
+ fclose(f);
+
+ if (state == cur_state)
+ return 0;
+
+ usleep(10000);
+ }
+}
diff --git a/src/kernel/tests/lib/tst_res.c b/src/kernel/tests/lib/tst_res.c
new file mode 100644
index 0000000..c35f41b
--- /dev/null
+++ b/src/kernel/tests/lib/tst_res.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ * AUTHOR : Kent Rogers (from Dave Fenner's original)
+ * CO-PILOT : Rich Logan
+ * DATE STARTED : 05/01/90 (rewritten 1/96)
+ * Copyright (c) 2009-2016 Cyril Hrubis <chrubis@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+#define _GNU_SOURCE
+
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "test.h"
+#include "safe_macros.h"
+#include "usctest.h"
+#include "ltp_priv.h"
+#include "tst_ansi_color.h"
+
+long TEST_RETURN;
+int TEST_ERRNO;
+void *TST_RET_PTR;
+
+#define VERBOSE 1
+#define NOPASS 3
+#define DISCARD 4
+
+#define MAXMESG 80 /* max length of internal messages */
+#define USERMESG 2048 /* max length of user message */
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
+ * message into the specified string.
+ *
+ * NOTE (garrcoop): arg_fmt _must_ be the last element in each function
+ * argument list that employs this.
+ */
+#define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) do {\
+ va_list ap; \
+ assert(arg_fmt != NULL); \
+ va_start(ap, arg_fmt); \
+ vsnprintf(buf, buf_len, arg_fmt, ap); \
+ va_end(ap); \
+ assert(strlen(buf) > 0); \
+} while (0)
+
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+# ifdef __ANDROID__
+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+ PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+# else
+/* MUSL: http://www.openwall.com/lists/musl/2017/02/20/5 */
+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP { {PTHREAD_MUTEX_RECURSIVE} }
+# endif
+#endif
+
+static pthread_mutex_t tmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+static void check_env(void);
+static void tst_condense(int tnum, int ttype, const char *tmesg);
+static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg);
+
+static int T_exitval = 0; /* exit value used by tst_exit() */
+static int passed_cnt;
+static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
+ /* NOPASS, DISCARD */
+
+static char Warn_mesg[MAXMESG]; /* holds warning messages */
+
+/*
+ * These are used for condensing output when NOT in verbose mode.
+ */
+static int Buffered = FALSE; /* TRUE if condensed output is currently */
+ /* buffered (i.e. not yet printed) */
+static char *Last_tcid; /* previous test case id */
+static int Last_num; /* previous test case number */
+static int Last_type; /* previous test result type */
+static char *Last_mesg; /* previous test result message */
+
+int tst_count = 0;
+
+/*
+ * These globals must be defined in the test.
+ */
+extern char *TCID; /* Test case identifier from the test source */
+extern int TST_TOTAL; /* Total number of test cases from the test */
+
+
+struct pair {
+ const char *name;
+ int val;
+};
+
+#define PAIR(def) [def] = {.name = #def, .val = def},
+#define STRPAIR(key, value) [key] = {.name = value, .val = key},
+
+#define PAIR_LOOKUP(pair_arr, idx) do { \
+ if (idx < 0 || (size_t)idx >= ARRAY_SIZE(pair_arr) || \
+ pair_arr[idx].name == NULL) \
+ return "???"; \
+ return pair_arr[idx].name; \
+} while (0)
+
+const char *strttype(int ttype)
+{
+ static const struct pair ttype_pairs[] = {
+ PAIR(TPASS)
+ PAIR(TFAIL)
+ PAIR(TBROK)
+ PAIR(TCONF)
+ PAIR(TWARN)
+ PAIR(TINFO)
+ };
+
+ PAIR_LOOKUP(ttype_pairs, TTYPE_RESULT(ttype));
+}
+
+#include "errnos.h"
+#include "signame.h"
+
+static void tst_res__(const char *file, const int lineno, int ttype,
+ const char *arg_fmt, ...)
+{
+ pthread_mutex_lock(&tmutex);
+
+ char tmesg[USERMESG];
+ int len = 0;
+ int ttype_result = TTYPE_RESULT(ttype);
+
+ if (file && (ttype_result != TPASS && ttype_result != TINFO))
+ len = sprintf(tmesg, "%s:%d: ", file, lineno);
+ EXPAND_VAR_ARGS(tmesg + len, arg_fmt, USERMESG - len);
+
+ /*
+ * Save the test result type by ORing ttype into the current exit
+ * value (used by tst_exit()).
+ */
+ T_exitval |= ttype_result;
+
+ if (ttype_result == TPASS)
+ passed_cnt++;
+
+ check_env();
+
+ /*
+ * Set the test case number and print the results, depending on the
+ * display type.
+ */
+ if (ttype_result == TWARN || ttype_result == TINFO) {
+ tst_print(TCID, 0, ttype, tmesg);
+ } else {
+ if (tst_count < 0)
+ tst_print(TCID, 0, TWARN,
+ "tst_res(): tst_count < 0 is not valid");
+
+ /*
+ * Process each display type.
+ */
+ switch (T_mode) {
+ case DISCARD:
+ break;
+ case NOPASS: /* filtered by tst_print() */
+ tst_condense(tst_count + 1, ttype, tmesg);
+ break;
+ default: /* VERBOSE */
+ tst_print(TCID, tst_count + 1, ttype, tmesg);
+ break;
+ }
+
+ tst_count++;
+ }
+
+ pthread_mutex_unlock(&tmutex);
+}
+
+static void tst_condense(int tnum, int ttype, const char *tmesg)
+{
+ int ttype_result = TTYPE_RESULT(ttype);
+
+ /*
+ * If this result is the same as the previous result, return.
+ */
+ if (Buffered == TRUE) {
+ if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
+ strcmp(Last_mesg, tmesg) == 0)
+ return;
+
+ /*
+ * This result is different from the previous result. First,
+ * print the previous result.
+ */
+ tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
+ free(Last_tcid);
+ free(Last_mesg);
+ }
+
+ /*
+ * If a file was specified, print the current result since we have no
+ * way of retaining the file contents for comparing with future
+ * results. Otherwise, buffer the current result info for next time.
+ */
+ Last_tcid = malloc(strlen(TCID) + 1);
+ strcpy(Last_tcid, TCID);
+ Last_num = tnum;
+ Last_type = ttype_result;
+ Last_mesg = malloc(strlen(tmesg) + 1);
+ strcpy(Last_mesg, tmesg);
+ Buffered = TRUE;
+}
+
+void tst_old_flush(void)
+{
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ pthread_mutex_lock(&tmutex);
+
+ /*
+ * Print out last line if in NOPASS mode.
+ */
+ if (Buffered == TRUE && T_mode == NOPASS) {
+ tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
+ Buffered = FALSE;
+ }
+
+ fflush(stdout);
+
+ pthread_mutex_unlock(&tmutex);
+}
+
+static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg)
+{
+ int err = errno;
+ const char *type;
+ int ttype_result = TTYPE_RESULT(ttype);
+ char message[USERMESG];
+ size_t size = 0;
+
+ /*
+ * Save the test result type by ORing ttype into the current exit value
+ * (used by tst_exit()). This is already done in tst_res(), but is
+ * also done here to catch internal warnings. For internal warnings,
+ * tst_print() is called directly with a case of TWARN.
+ */
+ T_exitval |= ttype_result;
+
+ /*
+ * If output mode is DISCARD, or if the output mode is NOPASS and this
+ * result is not one of FAIL, BROK, or WARN, just return. This check
+ * is necessary even though we check for DISCARD mode inside of
+ * tst_res(), since occasionally we get to this point without going
+ * through tst_res() (e.g. internal TWARN messages).
+ */
+ if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
+ ttype_result != TBROK
+ && ttype_result != TWARN))
+ return;
+
+ /*
+ * Build the result line and print it.
+ */
+ type = strttype(ttype);
+
+ if (T_mode == VERBOSE) {
+ size += snprintf(message + size, sizeof(message) - size,
+ "%-8s %4d ", tcid, tnum);
+ } else {
+ size += snprintf(message + size, sizeof(message) - size,
+ "%-8s %4d ", tcid, tnum);
+ }
+
+ if (size >= sizeof(message)) {
+ printf("%s: %i: line too long\n", __func__, __LINE__);
+ abort();
+ }
+
+ if (tst_color_enabled(STDOUT_FILENO))
+ size += snprintf(message + size, sizeof(message) - size,
+ "%s%s%s : %s", tst_ttype2color(ttype), type, ANSI_COLOR_RESET, tmesg);
+ else
+ size += snprintf(message + size, sizeof(message) - size,
+ "%s : %s", type, tmesg);
+
+ if (size >= sizeof(message)) {
+ printf("%s: %i: line too long\n", __func__, __LINE__);
+ abort();
+ }
+
+ if (ttype & TERRNO) {
+ size += snprintf(message + size, sizeof(message) - size,
+ ": errno=%s(%i): %s", tst_strerrno(err),
+ err, strerror(err));
+ }
+
+ if (size >= sizeof(message)) {
+ printf("%s: %i: line too long\n", __func__, __LINE__);
+ abort();
+ }
+
+ if (ttype & TTERRNO) {
+ size += snprintf(message + size, sizeof(message) - size,
+ ": TEST_ERRNO=%s(%i): %s",
+ tst_strerrno(TEST_ERRNO), (int)TEST_ERRNO,
+ strerror(TEST_ERRNO));
+ }
+
+ if (size >= sizeof(message)) {
+ printf("%s: %i: line too long\n", __func__, __LINE__);
+ abort();
+ }
+
+ if (ttype & TRERRNO) {
+ err = TEST_RETURN < 0 ? -(int)TEST_RETURN : (int)TEST_RETURN;
+ size += snprintf(message + size, sizeof(message) - size,
+ ": TEST_RETURN=%s(%i): %s",
+ tst_strerrno(err), err, strerror(err));
+ }
+
+ if (size + 1 >= sizeof(message)) {
+ printf("%s: %i: line too long\n", __func__, __LINE__);
+ abort();
+ }
+
+ message[size] = '\n';
+ message[size + 1] = '\0';
+
+ fputs(message, stdout);
+}
+
+static void check_env(void)
+{
+ static int first_time = 1;
+ char *value;
+
+ if (!first_time)
+ return;
+
+ first_time = 0;
+
+ /* BTOUTPUT not defined, use default */
+ if ((value = getenv(TOUTPUT)) == NULL) {
+ T_mode = VERBOSE;
+ return;
+ }
+
+ if (strcmp(value, TOUT_NOPASS_S) == 0) {
+ T_mode = NOPASS;
+ return;
+ }
+
+ if (strcmp(value, TOUT_DISCARD_S) == 0) {
+ T_mode = DISCARD;
+ return;
+ }
+
+ T_mode = VERBOSE;
+ return;
+}
+
+void tst_exit(void)
+{
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ pthread_mutex_lock(&tmutex);
+
+ tst_old_flush();
+
+ T_exitval &= ~TINFO;
+
+ if (T_exitval == TCONF && passed_cnt)
+ T_exitval &= ~TCONF;
+
+ exit(T_exitval);
+}
+
+pid_t tst_fork(void)
+{
+ pid_t child;
+
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ tst_old_flush();
+
+ child = fork();
+ if (child == 0)
+ T_exitval = 0;
+
+ return child;
+}
+
+void tst_record_childstatus(void (*cleanup)(void), pid_t child)
+{
+ int status, ttype_result;
+
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ SAFE_WAITPID(cleanup, child, &status, 0);
+
+ if (WIFEXITED(status)) {
+ ttype_result = WEXITSTATUS(status);
+ ttype_result = TTYPE_RESULT(ttype_result);
+ T_exitval |= ttype_result;
+
+ if (ttype_result == TPASS)
+ tst_resm(TINFO, "Child process returned TPASS");
+
+ if (ttype_result & TFAIL)
+ tst_resm(TINFO, "Child process returned TFAIL");
+
+ if (ttype_result & TBROK)
+ tst_resm(TINFO, "Child process returned TBROK");
+
+ if (ttype_result & TCONF)
+ tst_resm(TINFO, "Child process returned TCONF");
+
+ } else {
+ tst_brkm(TBROK, cleanup, "child process(%d) killed by "
+ "unexpected signal %s(%d)", child,
+ tst_strsig(WTERMSIG(status)), WTERMSIG(status));
+ }
+}
+
+pid_t tst_vfork(void)
+{
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ tst_old_flush();
+ return vfork();
+}
+
+/*
+ * Make tst_brk reentrant so that one can call the SAFE_* macros from within
+ * user-defined cleanup functions.
+ */
+static int tst_brk_entered = 0;
+
+static void tst_brk__(const char *file, const int lineno, int ttype,
+ void (*func)(void), const char *arg_fmt, ...)
+{
+ pthread_mutex_lock(&tmutex);
+
+ char tmesg[USERMESG];
+ int ttype_result = TTYPE_RESULT(ttype);
+
+ EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
+
+ /*
+ * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
+ */
+ if (ttype_result != TFAIL && ttype_result != TBROK &&
+ ttype_result != TCONF) {
+ sprintf(Warn_mesg, "%s: Invalid Type: %d. Using TBROK",
+ __func__, ttype_result);
+ tst_print(TCID, 0, TWARN, Warn_mesg);
+ /* Keep TERRNO, TTERRNO, etc. */
+ ttype = (ttype & ~ttype_result) | TBROK;
+ }
+
+ tst_res__(file, lineno, ttype, "%s", tmesg);
+ if (tst_brk_entered == 0) {
+ if (ttype_result == TCONF) {
+ tst_res__(file, lineno, ttype,
+ "Remaining cases not appropriate for "
+ "configuration");
+ } else if (ttype_result == TBROK) {
+ tst_res__(file, lineno, TBROK,
+ "Remaining cases broken");
+ }
+ }
+
+ /*
+ * If no cleanup function was specified, just return to the caller.
+ * Otherwise call the specified function.
+ */
+ if (func != NULL) {
+ tst_brk_entered++;
+ (*func) ();
+ tst_brk_entered--;
+ }
+ if (tst_brk_entered == 0)
+ tst_exit();
+
+ pthread_mutex_unlock(&tmutex);
+}
+
+void tst_resm_(const char *file, const int lineno, int ttype,
+ const char *arg_fmt, ...)
+{
+ char tmesg[USERMESG];
+
+ EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
+
+ if (tst_test)
+ tst_res_(file, lineno, ttype, "%s", tmesg);
+ else
+ tst_res__(file, lineno, ttype, "%s", tmesg);
+}
+
+typedef void (*tst_res_func_t)(const char *file, const int lineno,
+ int ttype, const char *fmt, ...);
+
+void tst_resm_hexd_(const char *file, const int lineno, int ttype,
+ const void *buf, size_t size, const char *arg_fmt, ...)
+{
+ char tmesg[USERMESG];
+ static const size_t symb_num = 2; /* xx */
+ static const size_t size_max = 16;
+ size_t offset;
+ size_t i;
+ char *pmesg = tmesg;
+ tst_res_func_t res_func;
+
+ if (tst_test)
+ res_func = tst_res_;
+ else
+ res_func = tst_res__;
+
+ EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
+ offset = strlen(tmesg);
+
+ if (size > size_max || size == 0 ||
+ (offset + size * (symb_num + 1)) >= USERMESG)
+ res_func(file, lineno, ttype, "%s", tmesg);
+ else
+ pmesg += offset;
+
+ for (i = 0; i < size; ++i) {
+ /* add space before byte except first one */
+ if (pmesg != tmesg)
+ *(pmesg++) = ' ';
+
+ sprintf(pmesg, "%02x", ((unsigned char *)buf)[i]);
+ pmesg += symb_num;
+ if ((i + 1) % size_max == 0 || i + 1 == size) {
+ res_func(file, lineno, ttype, "%s", tmesg);
+ pmesg = tmesg;
+ }
+ }
+}
+
+void tst_brkm_(const char *file, const int lineno, int ttype,
+ void (*func)(void), const char *arg_fmt, ...)
+{
+ char tmesg[USERMESG];
+
+ EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
+
+ if (tst_test) {
+ if (func) {
+ tst_brk_(file, lineno, TBROK,
+ "Non-NULL cleanup in newlib!");
+ }
+
+ tst_brk_(file, lineno, ttype, "%s", tmesg);
+ } else {
+ tst_brk__(file, lineno, ttype, func, "%s", tmesg);
+ }
+
+ /* Shouldn't be reached, but fixes build time warnings about noreturn. */
+ abort();
+}
+
+void tst_require_root(void)
+{
+ NO_NEWLIB_ASSERT("Unknown", 0);
+
+ if (geteuid() != 0)
+ tst_brkm(TCONF, NULL, "Test needs to be run as root");
+}
diff --git a/src/kernel/tests/lib/tst_resource.c b/src/kernel/tests/lib/tst_resource.c
new file mode 100644
index 0000000..0b9b381
--- /dev/null
+++ b/src/kernel/tests/lib/tst_resource.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 Cyril Hrubis chrubis@suse.cz
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pthread.h>
+#include "test.h"
+#include "old_resource.h"
+#include "ltp_priv.h"
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+static pthread_mutex_t tmutex = PTHREAD_MUTEX_INITIALIZER;
+static char dataroot[PATH_MAX];
+extern char *TCID;
+
+static void tst_dataroot_init(void)
+{
+ const char *ltproot = getenv("LTPROOT");
+ char curdir[PATH_MAX];
+ const char *startdir;
+ int ret;
+
+ /* 1. if LTPROOT is set, use $LTPROOT/testcases/data/$TCID
+ * 2. else if startwd is set by tst_tmpdir(), use $STARWD/datafiles
+ * 3. else use $CWD/datafiles */
+ if (ltproot) {
+ ret = snprintf(dataroot, PATH_MAX, "%s/testcases/data/%s",
+ ltproot, TCID);
+ } else {
+ startdir = tst_get_startwd();
+ if (startdir[0] == 0) {
+ if (getcwd(curdir, PATH_MAX) == NULL) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "tst_dataroot getcwd");
+ return;
+ }
+ startdir = curdir;
+ }
+ ret = snprintf(dataroot, PATH_MAX, "%s/datafiles", startdir);
+ }
+
+ if (ret < 0 || ret >= PATH_MAX)
+ tst_brkm(TBROK, NULL, "tst_dataroot snprintf: %d", ret);
+}
+
+const char *tst_dataroot(void)
+{
+ if (dataroot[0] == 0) {
+ pthread_mutex_lock(&tmutex);
+ if (dataroot[0] == 0)
+ tst_dataroot_init();
+ pthread_mutex_unlock(&tmutex);
+ }
+ return dataroot;
+}
+
+static int file_copy(const char *file, const int lineno,
+ void (*cleanup_fn)(void), const char *path,
+ const char *filename, const char *dest)
+{
+ size_t len = strlen(path) + strlen(filename) + 2;
+ char buf[len];
+
+ snprintf(buf, sizeof(buf), "%s/%s", path, filename);
+
+ /* check if file exists */
+ if (access(buf, R_OK))
+ return 0;
+
+ safe_cp(file, lineno, cleanup_fn, buf, dest);
+
+ return 1;
+}
+
+void tst_resource_copy(const char *file, const int lineno,
+ void (*cleanup_fn)(void),
+ const char *filename, const char *dest)
+{
+ if (!tst_tmpdir_created()) {
+ tst_brkm(TBROK, cleanup_fn,
+ "Temporary directory doesn't exist at %s:%d",
+ file, lineno);
+ return;
+ }
+
+ if (dest == NULL)
+ dest = ".";
+
+ const char *ltproot = getenv("LTPROOT");
+ const char *dataroot = tst_dataroot();
+
+ /* look for data files in $LTP_DATAROOT, $LTPROOT/testcases/bin
+ * and $CWD */
+ if (file_copy(file, lineno, cleanup_fn, dataroot, filename, dest))
+ return;
+
+ if (ltproot != NULL) {
+ char buf[strlen(ltproot) + 64];
+
+ snprintf(buf, sizeof(buf), "%s/testcases/bin", ltproot);
+
+ if (file_copy(file, lineno, cleanup_fn, buf, filename, dest))
+ return;
+ }
+
+ /* try directory test started in as last resort */
+ const char *startwd = tst_get_startwd();
+ if (file_copy(file, lineno, cleanup_fn, startwd, filename, dest))
+ return;
+
+ tst_brkm(TBROK, cleanup_fn, "Failed to copy resource '%s' at %s:%d",
+ filename, file, lineno);
+}
diff --git a/src/kernel/tests/lib/tst_safe_macros.c b/src/kernel/tests/lib/tst_safe_macros.c
new file mode 100644
index 0000000..25c37df
--- /dev/null
+++ b/src/kernel/tests/lib/tst_safe_macros.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/ptrace.h>
+#include "config.h"
+#ifdef HAVE_SYS_FANOTIFY_H
+# include <sys/fanotify.h>
+#endif
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "lapi/setns.h"
+#include "tst_safe_macros.h"
+#include "lapi/personality.h"
+
+int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid)
+{
+ int rval;
+
+ rval = setpgid(pid, pgid);
+ if (rval) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: setpgid(%i, %i) failed",
+ file, lineno, pid, pgid);
+ }
+
+ return rval;
+}
+
+pid_t safe_getpgid(const char *file, const int lineno, pid_t pid)
+{
+ pid_t pgid;
+
+ pgid = getpgid(pid);
+ if (pgid == -1) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: getpgid(%i) failed", file, lineno, pid);
+ }
+
+ return pgid;
+}
+
+int safe_fanotify_init(const char *file, const int lineno,
+ unsigned int flags, unsigned int event_f_flags)
+{
+ int rval;
+
+#ifdef HAVE_SYS_FANOTIFY_H
+ rval = fanotify_init(flags, event_f_flags);
+
+ if (rval == -1) {
+ if (errno == ENOSYS) {
+ tst_brk(TCONF,
+ "fanotify is not configured in this kernel.");
+ }
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: fanotify_init() failed", file, lineno);
+ }
+#else
+ tst_brk(TCONF, "Header <sys/fanotify.h> is not present");
+#endif /* HAVE_SYS_FANOTIFY_H */
+
+ return rval;
+}
+
+int safe_personality(const char *filename, unsigned int lineno,
+ unsigned long persona)
+{
+ int prev_persona = personality(persona);
+
+ if (prev_persona < 0) {
+ tst_brk_(filename, lineno, TBROK | TERRNO,
+ "persona(%ld) failed", persona);
+ }
+
+ return prev_persona;
+}
+
+int safe_setregid(const char *file, const int lineno,
+ gid_t rgid, gid_t egid)
+{
+ int rval;
+
+ rval = setregid(rgid, egid);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "setregid(%li, %li) failed",
+ (long)rgid, (long)egid);
+ }
+
+ return rval;
+}
+
+
+int safe_setreuid(const char *file, const int lineno,
+ uid_t ruid, uid_t euid)
+{
+ int rval;
+
+ rval = setreuid(ruid, euid);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "setreuid(%li, %li) failed",
+ (long)ruid, (long)euid);
+ }
+
+ return rval;
+}
+
+
+int safe_sigaction(const char *file, const int lineno,
+ int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+{
+ int rval;
+
+ rval = sigaction(signum, act, oldact);
+
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "sigaction(%s (%d), %p, %p) failed",
+ tst_strsig(signum), signum, act, oldact);
+ }
+
+ return rval;
+}
+
+void safe_sigaddset(const char *file, const int lineno,
+ sigset_t *sigs, int signo)
+{
+ int rval;
+
+ rval = sigaddset(sigs, signo);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "sigaddset() %s (%i) failed",
+ tst_strsig(signo), signo);
+ }
+}
+
+void safe_sigdelset(const char *file, const int lineno,
+ sigset_t *sigs, int signo)
+{
+ int rval;
+
+ rval = sigdelset(sigs, signo);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "sigdelset() %s (%i) failed",
+ tst_strsig(signo), signo);
+ }
+}
+
+void safe_sigemptyset(const char *file, const int lineno,
+ sigset_t *sigs)
+{
+ int rval;
+
+ rval = sigemptyset(sigs);
+ if (rval == -1)
+ tst_brk_(file, lineno, TBROK | TERRNO, "sigemptyset() failed");
+}
+
+void safe_sigfillset(const char *file, const int lineno,
+ sigset_t *sigs)
+{
+ int rval;
+
+ rval = sigfillset(sigs);
+ if (rval == -1)
+ tst_brk_(file, lineno, TBROK | TERRNO, "sigfillset() failed");
+}
+
+static const char *strhow(int how)
+{
+ switch (how) {
+ case SIG_BLOCK:
+ return "SIG_BLOCK";
+ case SIG_UNBLOCK:
+ return "SIG_UNBLOCK";
+ case SIG_SETMASK:
+ return "SIG_SETMASK";
+ default:
+ return "???";
+ }
+}
+
+void safe_sigprocmask(const char *file, const int lineno,
+ int how, sigset_t *set, sigset_t *oldset)
+{
+ int rval;
+
+ rval = sigprocmask(how, set, oldset);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "sigprocmask(%s, %p, %p)", strhow(how), set, oldset);
+ }
+}
+
+void safe_sigwait(const char *file, const int lineno,
+ sigset_t *set, int *sig)
+{
+ int rval;
+
+ rval = sigwait(set, sig);
+ if (rval != 0) {
+ errno = rval;
+ tst_brk_(file, lineno, TBROK, "sigwait(%p, %p)", set, sig);
+ }
+}
+
+struct group *safe_getgrnam(const char *file, const int lineno,
+ const char *name)
+{
+ struct group *rval;
+
+ errno = 0;
+ rval = getgrnam(name);
+ if (rval == NULL) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "getgrnam(%s) failed", name);
+ }
+
+ return rval;
+}
+
+struct group *safe_getgrnam_fallback(const char *file, const int lineno,
+ const char *name, const char *fallback)
+{
+ struct group *rval;
+
+ errno = 0;
+ rval = getgrnam(name);
+ if (rval == NULL) {
+ tst_res_(file, lineno, TINFO,
+ "getgrnam(%s) failed - try fallback %s",
+ name, fallback);
+ rval = safe_getgrnam(file, lineno, fallback);
+ }
+
+ return rval;
+}
+
+struct group *safe_getgrgid(const char *file, const int lineno, gid_t gid)
+{
+ struct group *rval;
+
+ errno = 0;
+ rval = getgrgid(gid);
+ if (rval == NULL) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "getgrgid(%li) failed", (long)gid);
+ }
+
+ return rval;
+}
+
+int safe_chroot(const char *file, const int lineno, const char *path)
+{
+ int rval;
+
+ rval = chroot(path);
+ if (rval == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "chroot(%s) failed", path);
+ }
+
+ return rval;
+}
+
+void safe_unshare(const char *file, const int lineno, int flags)
+{
+ int res;
+
+ res = unshare(flags);
+ if (res == -1) {
+ if (errno == EINVAL) {
+ tst_brk_(file, lineno, TCONF | TERRNO,
+ "unshare(%d) unsupported", flags);
+ } else {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "unshare(%d) failed", flags);
+ }
+ }
+}
+
+void safe_setns(const char *file, const int lineno, int fd, int nstype)
+{
+ int ret;
+
+ ret = setns(fd, nstype);
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO, "setns(%i, %i) failed",
+ fd, nstype);
+ }
+}
+
+long tst_safe_ptrace(const char *file, const int lineno, int req, pid_t pid,
+ void *addr, void *data)
+{
+ long ret;
+
+ errno = 0;
+ ret = ptrace(req, pid, addr, data);
+
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO, "ptrace() failed");
+ } else if (ret) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "Invalid ptrace() return value %ld", ret);
+ }
+
+ return ret;
+}
+
+int safe_pipe2(const char *file, const int lineno, int fildes[2], int flags)
+{
+ int ret;
+
+ ret = pipe2(fildes, flags);
+ if (ret == -1) {
+ tst_brk_(file, lineno, TBROK | TERRNO,
+ "pipe2({%d,%d}) failed with flag(%d)",
+ fildes[0], fildes[1], flags);
+ }
+
+ return ret;
+}
diff --git a/src/kernel/tests/lib/tst_safe_sysv_ipc.c b/src/kernel/tests/lib/tst_safe_sysv_ipc.c
new file mode 100644
index 0000000..30b5f6e
--- /dev/null
+++ b/src/kernel/tests/lib/tst_safe_sysv_ipc.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Xiao yang <yangx.jy@cn.fujitsu.com>
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_safe_sysv_ipc.h"
+
+/*
+ * The IPC_STAT, IPC_SET and IPC_RMID can return either 0 or -1.
+ *
+ * Linux specific cmds either returns -1 on failure or positive integer
+ * either index into an kernel array or shared primitive indentifier.
+ */
+static int ret_check(int cmd, int ret)
+{
+ switch (cmd) {
+ case IPC_STAT:
+ case IPC_SET:
+ case IPC_RMID:
+ return ret != 0;
+ default:
+ return ret == -1;
+ }
+}
+
+int safe_msgget(const char *file, const int lineno, key_t key, int msgflg)
+{
+ int rval;
+
+ rval = msgget(key, msgflg);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO, "%s:%d: msgget(%i, %x) failed",
+ file, lineno, (int)key, msgflg);
+ }
+
+ return rval;
+}
+
+int safe_msgsnd(const char *file, const int lineno, int msqid, const void *msgp,
+ size_t msgsz, int msgflg)
+{
+ int rval;
+
+ rval = msgsnd(msqid, msgp, msgsz, msgflg);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: msgsnd(%i, %p, %zu, %x) failed",
+ file, lineno, msqid, msgp, msgsz, msgflg);
+ }
+
+ return rval;
+}
+
+ssize_t safe_msgrcv(const char *file, const int lineno, int msqid, void *msgp,
+ size_t msgsz, long msgtyp, int msgflg)
+{
+ ssize_t rval;
+
+ rval = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: msgrcv(%i, %p, %zu, %li, %x) failed",
+ file, lineno, msqid, msgp, msgsz, msgtyp, msgflg);
+ }
+
+ return rval;
+}
+
+int safe_msgctl(const char *file, const int lineno, int msqid, int cmd,
+ struct msqid_ds *buf)
+{
+ int rval;
+
+ rval = msgctl(msqid, cmd, buf);
+ if (ret_check(cmd, rval)) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: msgctl(%i, %i, %p) = %i failed",
+ file, lineno, msqid, cmd, buf, rval);
+ }
+
+
+ return rval;
+}
+
+int safe_shmget(const char *file, const int lineno, key_t key, size_t size,
+ int shmflg)
+{
+ int rval;
+
+ rval = shmget(key, size, shmflg);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO, "%s:%d: shmget(%i, %zu, %x) failed",
+ file, lineno, (int)key, size, shmflg);
+ }
+
+ return rval;
+}
+
+void *safe_shmat(const char *file, const int lineno, int shmid,
+ const void *shmaddr, int shmflg)
+{
+ void *rval;
+
+ rval = shmat(shmid, shmaddr, shmflg);
+ if (rval == (void *)-1) {
+ tst_brk(TBROK | TERRNO, "%s:%d: shmat(%i, %p, %x) failed",
+ file, lineno, shmid, shmaddr, shmflg);
+ }
+
+ return rval;
+}
+
+int safe_shmdt(const char *file, const int lineno, const void *shmaddr)
+{
+ int rval;
+
+ rval = shmdt(shmaddr);
+ if (rval == -1) {
+ tst_brk(TBROK | TERRNO, "%s:%d: shmdt(%p) failed",
+ file, lineno, shmaddr);
+ }
+
+ return rval;
+}
+
+int safe_shmctl(const char *file, const int lineno, int shmid, int cmd,
+ struct shmid_ds *buf)
+{
+ int rval;
+
+ rval = shmctl(shmid, cmd, buf);
+ if (ret_check(cmd, rval)) {
+ tst_brk(TBROK | TERRNO,
+ "%s:%d: shmctl(%i, %i, %p) = %i failed",
+ file, lineno, shmid, cmd, buf, rval);
+ }
+
+ return rval;
+}
diff --git a/src/kernel/tests/lib/tst_safe_timerfd.c b/src/kernel/tests/lib/tst_safe_timerfd.c
new file mode 100644
index 0000000..ffe7b2e
--- /dev/null
+++ b/src/kernel/tests/lib/tst_safe_timerfd.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
+ */
+
+#include "tst_safe_timerfd.h"
+#include "lapi/timerfd.h"
+#include "tst_clocks.h"
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+#define TTYPE (errno == ENOTSUP ? TCONF : TBROK)
+
+int safe_timerfd_create(const char *file, const int lineno,
+ int clockid, int flags)
+{
+ int fd;
+
+ fd = timerfd_create(clockid, flags);
+ if (fd < 0) {
+ tst_brk(TTYPE | TERRNO, "%s:%d timerfd_create(%s) failed",
+ file, lineno, tst_clock_name(clockid));
+ }
+
+ return fd;
+}
+
+int safe_timerfd_gettime(const char *file, const int lineno,
+ int fd, struct itimerspec *curr_value)
+{
+ int rval;
+
+ rval = timerfd_gettime(fd, curr_value);
+ if (rval != 0) {
+ tst_brk(TTYPE | TERRNO, "%s:%d timerfd_gettime() failed",
+ file, lineno);
+ }
+
+ return rval;
+}
+
+int safe_timerfd_settime(const char *file, const int lineno,
+ int fd, int flags,
+ const struct itimerspec *new_value,
+ struct itimerspec *old_value)
+{
+ int rval;
+
+ rval = timerfd_settime(fd, flags, new_value, old_value);
+ if (rval != 0) {
+ tst_brk(TTYPE | TERRNO, "%s:%d timerfd_settime() failed",
+ file, lineno);
+ }
+
+ return rval;
+}
diff --git a/src/kernel/tests/lib/tst_sig.c b/src/kernel/tests/lib/tst_sig.c
new file mode 100644
index 0000000..6d77aea
--- /dev/null
+++ b/src/kernel/tests/lib/tst_sig.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: tst_sig.c,v 1.13 2009/08/28 09:29:01 vapier Exp $ */
+
+/*****************************************************************************
+ OS Testing - Silicon Graphics, Inc.
+
+ FUNCTION IDENTIFIER : tst_sig Set up for unexpected signals.
+
+ AUTHOR : David D. Fenner
+
+ CO-PILOT : Bill Roske
+
+ DATE STARTED : 06/06/90
+
+ This module may be linked with c-modules requiring unexpected
+ signal handling. The parameters to tst_sig are as follows:
+
+ fork_flag - set to FORK or NOFORK depending upon whether the
+ calling program executes a fork() system call. It
+ is normally the case that the calling program treats
+ SIGCHLD as an expected signal if fork() is being used.
+
+ handler - a pointer to the unexpected signal handler to
+ be executed after an unexpected signal has been
+ detected. If handler is set to DEF_HANDLER, a
+ default handler is used. This routine should be
+ declared as function returning an int.
+
+ cleanup - a pointer to a cleanup routine to be executed
+ by the unexpected signal handler before tst_exit is
+ called. This parameter is set to NULL if no cleanup
+ routine is required. An external variable, T_cleanup
+ is set so that other user-defined handlers have
+ access to the cleanup routine. This routine should be
+ declared as returning type void.
+
+***************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include "test.h"
+#include "lapi/signal.h"
+
+#define MAXMESG 150 /* size of mesg string sent to tst_res */
+
+static void (*T_cleanup) ();
+
+static void def_handler(); /* default signal handler */
+static void (*tst_setup_signal(int, void (*)(int))) (int);
+
+/****************************************************************************
+ * tst_sig() : set-up to catch unexpected signals. fork_flag is set to NOFORK
+ * if SIGCHLD is to be an "unexpected signal", otherwise it is set to
+ * FORK. cleanup points to a cleanup routine to be executed before
+ * tst_exit is called (cleanup is set to NULL if no cleanup is desired).
+ * handler is a pointer to the signal handling routine (if handler is
+ * set to NULL, a default handler is used).
+ ***************************************************************************/
+
+void tst_sig(int fork_flag, void (*handler) (), void (*cleanup) ())
+{
+ int sig;
+#ifdef _SC_SIGRT_MIN
+ long sigrtmin, sigrtmax;
+#endif
+
+ /*
+ * save T_cleanup and handler function pointers
+ */
+ T_cleanup = cleanup; /* used by default handler */
+
+ if (handler == DEF_HANDLER) {
+ /* use default handler */
+ handler = def_handler;
+ }
+#ifdef _SC_SIGRT_MIN
+ sigrtmin = sysconf(_SC_SIGRT_MIN);
+ sigrtmax = sysconf(_SC_SIGRT_MAX);
+#endif
+
+ /*
+ * now loop through all signals and set the handlers
+ */
+
+ for (sig = 1; sig < NSIG; sig++) {
+ /*
+ * SIGKILL is never unexpected.
+ * SIGCHLD is only unexpected when
+ * no forking is being done.
+ * SIGINFO is used for file quotas and should be expected
+ */
+
+#ifdef _SC_SIGRT_MIN
+ if (sig >= sigrtmin && sig <= sigrtmax)
+ continue;
+#endif
+
+ switch (sig) {
+ case SIGKILL:
+ case SIGSTOP:
+ case SIGCONT:
+#if !defined(_SC_SIGRT_MIN) && defined(__SIGRTMIN) && defined(__SIGRTMAX)
+ /* Ignore all real-time signals */
+ case __SIGRTMIN:
+ case __SIGRTMIN + 1:
+ case __SIGRTMIN + 2:
+ case __SIGRTMIN + 3:
+ case __SIGRTMIN + 4:
+ case __SIGRTMIN + 5:
+ case __SIGRTMIN + 6:
+ case __SIGRTMIN + 7:
+ case __SIGRTMIN + 8:
+ case __SIGRTMIN + 9:
+ case __SIGRTMIN + 10:
+ case __SIGRTMIN + 11:
+ case __SIGRTMIN + 12:
+ case __SIGRTMIN + 13:
+ case __SIGRTMIN + 14:
+ case __SIGRTMIN + 15:
+/* __SIGRTMIN is 37 on HPPA rather than 32 *
+ * as on i386, etc. */
+#if !defined(__hppa__)
+ case __SIGRTMAX - 15:
+ case __SIGRTMAX - 14:
+ case __SIGRTMAX - 13:
+ case __SIGRTMAX - 12:
+ case __SIGRTMAX - 11:
+#endif
+ case __SIGRTMAX - 10:
+ case __SIGRTMAX - 9:
+ case __SIGRTMAX - 8:
+ case __SIGRTMAX - 7:
+ case __SIGRTMAX - 6:
+ case __SIGRTMAX - 5:
+ case __SIGRTMAX - 4:
+ case __SIGRTMAX - 3:
+ case __SIGRTMAX - 2:
+ case __SIGRTMAX - 1:
+ case __SIGRTMAX:
+#endif
+#ifdef SIGSWAP
+ case SIGSWAP:
+#endif /* SIGSWAP */
+
+#ifdef SIGCKPT
+ case SIGCKPT:
+#endif
+#ifdef SIGRESTART
+ case SIGRESTART:
+#endif
+ /*
+ * pthread-private signals SIGPTINTR and SIGPTRESCHED.
+ * Setting a handler for these signals is disallowed when
+ * the binary is linked against libpthread.
+ */
+#ifdef SIGPTINTR
+ case SIGPTINTR:
+#endif /* SIGPTINTR */
+#ifdef SIGPTRESCHED
+ case SIGPTRESCHED:
+#endif /* SIGPTRESCHED */
+#ifdef _SIGRESERVE
+ case _SIGRESERVE:
+#endif
+#ifdef _SIGDIL
+ case _SIGDIL:
+#endif
+#ifdef _SIGCANCEL
+ case _SIGCANCEL:
+#endif
+#ifdef _SIGGFAULT
+ case _SIGGFAULT:
+#endif
+ break;
+
+ case SIGCHLD:
+ if (fork_flag == FORK)
+ continue;
+
+ default:
+ if (tst_setup_signal(sig, handler) == SIG_ERR)
+ tst_resm(TWARN | TERRNO,
+ "signal failed for signal %d", sig);
+ break;
+ }
+ }
+}
+
+/****************************************************************************
+ * def_handler() : default signal handler that is invoked when
+ * an unexpected signal is caught.
+ ***************************************************************************/
+
+static void def_handler(int sig)
+{
+ /*
+ * Break remaining test cases, do any cleanup, then exit
+ */
+ tst_brkm(TBROK, T_cleanup,
+ "unexpected signal %s(%d) received (pid = %d).",
+ tst_strsig(sig), sig, getpid());
+}
+
+/*
+ * tst_setup_signal - A function like signal(), but we have
+ * control over its personality.
+ */
+static void (*tst_setup_signal(int sig, void (*handler) (int))) (int) {
+ struct sigaction my_act, old_act;
+ int ret;
+
+ my_act.sa_handler = handler;
+ my_act.sa_flags = SA_RESTART;
+ sigemptyset(&my_act.sa_mask);
+
+ ret = sigaction(sig, &my_act, &old_act);
+
+ if (ret == 0)
+ return old_act.sa_handler;
+ else
+ return SIG_ERR;
+}
diff --git a/src/kernel/tests/lib/tst_sig_proc.c b/src/kernel/tests/lib/tst_sig_proc.c
new file mode 100644
index 0000000..509418a
--- /dev/null
+++ b/src/kernel/tests/lib/tst_sig_proc.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2016 Linux Test Project
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "tst_sig_proc.h"
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+pid_t create_sig_proc(int sig, int count, unsigned int usec)
+{
+ pid_t pid, cpid;
+
+ pid = getpid();
+ cpid = SAFE_FORK();
+
+ if (cpid == 0) {
+ while (count-- > 0) {
+ usleep(usec);
+ if (kill(pid, sig) == -1)
+ break;
+ }
+ exit(0);
+ }
+
+ return cpid;
+}
diff --git a/src/kernel/tests/lib/tst_status.c b/src/kernel/tests/lib/tst_status.c
new file mode 100644
index 0000000..f1affea
--- /dev/null
+++ b/src/kernel/tests/lib/tst_status.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+static char buf[32];
+
+const char *exited(int status)
+{
+ snprintf(buf, sizeof(buf), "exited with %i", WEXITSTATUS(status));
+
+ return buf;
+}
+
+const char *signaled(int status)
+{
+ snprintf(buf, sizeof(buf), "killed by %s", tst_strsig(status));
+
+ return buf;
+}
+
+const char *invalid(int status)
+{
+ snprintf(buf, sizeof(buf), "invalid status 0x%x", status);
+
+ return buf;
+}
+
+const char *tst_strstatus(int status)
+{
+ if (WIFEXITED(status))
+ return exited(status);
+
+ if (WIFSIGNALED(status))
+ return signaled(status);
+
+ if (WIFSTOPPED(status))
+ return "is stopped";
+
+ if (WIFCONTINUED(status))
+ return "is resumed";
+
+ return invalid(status);
+}
diff --git a/src/kernel/tests/lib/tst_supported_fs_types.c b/src/kernel/tests/lib/tst_supported_fs_types.c
new file mode 100644
index 0000000..00ede54
--- /dev/null
+++ b/src/kernel/tests/lib/tst_supported_fs_types.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_fs.h"
+
+static const char *const fs_type_whitelist[] = {
+ "ext2",
+ "ext3",
+ "ext4",
+ "xfs",
+ "btrfs",
+ "vfat",
+ "exfat",
+ "ntfs",
+ NULL
+};
+
+static const char *fs_types[ARRAY_SIZE(fs_type_whitelist)];
+
+static int has_mkfs(const char *fs_type)
+{
+ char buf[128];
+ int ret;
+
+ sprintf(buf, "mkfs.%s >/dev/null 2>&1", fs_type);
+
+ ret = tst_system(buf);
+
+ if (WEXITSTATUS(ret) == 127) {
+ tst_res(TINFO, "mkfs.%s does not exist", fs_type);
+ return 0;
+ }
+
+ tst_res(TINFO, "mkfs.%s does exist", fs_type);
+ return 1;
+}
+
+static int has_kernel_support(const char *fs_type, int flags)
+{
+ static int fuse_supported = -1;
+ const char *tmpdir = getenv("TMPDIR");
+ char buf[128];
+ int ret;
+
+ if (!tmpdir)
+ tmpdir = "/tmp";
+
+ mount("/dev/zero", tmpdir, fs_type, 0, NULL);
+ if (errno != ENODEV) {
+ tst_res(TINFO, "Kernel supports %s", fs_type);
+ return 1;
+ }
+
+ /* Is FUSE supported by kernel? */
+ if (fuse_supported == -1) {
+ ret = open("/dev/fuse", O_RDWR);
+ if (ret < 0) {
+ fuse_supported = 0;
+ } else {
+ fuse_supported = 1;
+ SAFE_CLOSE(ret);
+ }
+ }
+
+ if (!fuse_supported)
+ return 0;
+
+ /* Is FUSE implementation installed? */
+ sprintf(buf, "mount.%s >/dev/null 2>&1", fs_type);
+
+ ret = tst_system(buf);
+ if (WEXITSTATUS(ret) == 127) {
+ tst_res(TINFO, "Filesystem %s is not supported", fs_type);
+ return 0;
+ }
+
+ if (flags & TST_FS_SKIP_FUSE) {
+ tst_res(TINFO, "Skipping FUSE as requested by the test");
+ return 0;
+ }
+
+ tst_res(TINFO, "FUSE does support %s", fs_type);
+ return 1;
+}
+
+int tst_fs_is_supported(const char *fs_type, int flags)
+{
+ return has_kernel_support(fs_type, flags) && has_mkfs(fs_type);
+}
+
+const char **tst_get_supported_fs_types(int flags)
+{
+ unsigned int i, j = 0;
+
+ for (i = 0; fs_type_whitelist[i]; i++) {
+ if (tst_fs_is_supported(fs_type_whitelist[i], flags))
+ fs_types[j++] = fs_type_whitelist[i];
+ }
+
+ return fs_types;
+}
diff --git a/src/kernel/tests/lib/tst_sys_conf.c b/src/kernel/tests/lib/tst_sys_conf.c
new file mode 100644
index 0000000..4ad9f8b
--- /dev/null
+++ b/src/kernel/tests/lib/tst_sys_conf.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 Jan Stancek <jstancek@redhat.com>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_sys_conf.h"
+
+static struct tst_sys_conf *save_restore_data;
+
+void tst_sys_conf_dump(void)
+{
+ struct tst_sys_conf *i;
+
+ for (i = save_restore_data; i; i = i->next)
+ tst_res(TINFO, "%s = %s", i->path, i->value);
+}
+
+int tst_sys_conf_save_str(const char *path, const char *value)
+{
+ struct tst_sys_conf *n = SAFE_MALLOC(sizeof(*n));
+
+ strncpy(n->path, path, sizeof(n->path)-1);
+ strncpy(n->value, value, sizeof(n->value)-1);
+
+ n->path[sizeof(n->path) - 1] = 0;
+ n->value[sizeof(n->value) - 1] = 0;
+
+ n->next = save_restore_data;
+ save_restore_data = n;
+
+ return 0;
+}
+
+int tst_sys_conf_save(const char *path)
+{
+ char line[PATH_MAX];
+ FILE *fp;
+ void *ret;
+ char flag;
+
+ if (!path)
+ tst_brk(TBROK, "path is empty");
+
+ flag = path[0];
+ if (flag == '?' || flag == '!')
+ path++;
+
+ if (access(path, F_OK) != 0) {
+ switch (flag) {
+ case '?':
+ tst_res(TINFO, "Path not found: '%s'", path);
+ break;
+ case '!':
+ tst_brk(TBROK|TERRNO, "Path not found: '%s'", path);
+ break;
+ default:
+ tst_brk(TCONF|TERRNO, "Path not found: '%s'", path);
+ }
+ return 1;
+ }
+
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ if (flag == '?')
+ return 1;
+
+ tst_brk(TBROK | TERRNO, "Failed to open FILE '%s' for reading",
+ path);
+ return 1;
+ }
+
+ ret = fgets(line, sizeof(line), fp);
+ fclose(fp);
+
+ if (ret == NULL) {
+ if (flag == '?')
+ return 1;
+
+ tst_brk(TBROK | TERRNO, "Failed to read anything from '%s'",
+ path);
+ }
+
+ return tst_sys_conf_save_str(path, line);
+}
+
+void tst_sys_conf_restore(int verbose)
+{
+ struct tst_sys_conf *i;
+
+ for (i = save_restore_data; i; i = i->next) {
+ if (verbose) {
+ tst_res(TINFO, "Restoring conf.: %s -> %s\n",
+ i->path, i->value);
+ }
+ FILE_PRINTF(i->path, "%s", i->value);
+ }
+}
+
diff --git a/src/kernel/tests/lib/tst_taint.c b/src/kernel/tests/lib/tst_taint.c
new file mode 100644
index 0000000..49146aa
--- /dev/null
+++ b/src/kernel/tests/lib/tst_taint.c
@@ -0,0 +1,107 @@
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+#include "tst_taint.h"
+#include "tst_safe_stdio.h"
+
+#define TAINT_FILE "/proc/sys/kernel/tainted"
+
+static unsigned int taint_mask = -1;
+
+static unsigned int tst_taint_read(void)
+{
+ unsigned int val;
+
+ SAFE_FILE_SCANF(TAINT_FILE, "%u", &val);
+
+ return val;
+}
+
+static int tst_taint_check_kver(unsigned int mask)
+{
+ int r1;
+ int r2;
+ int r3 = 0;
+
+ if (mask & TST_TAINT_X) {
+ r1 = 4;
+ r2 = 15;
+ } else if (mask & TST_TAINT_K) {
+ r1 = 4;
+ r2 = 0;
+ } else if (mask & TST_TAINT_L) {
+ r1 = 3;
+ r2 = 17;
+ } else if (mask & TST_TAINT_E) {
+ r1 = 3;
+ r2 = 15;
+ } else if (mask & TST_TAINT_O) {
+ r1 = 3;
+ r2 = 2;
+ } else if (mask & TST_TAINT_I) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 35;
+ } else if (mask & TST_TAINT_C) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 28;
+ } else if (mask & TST_TAINT_W) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 26;
+ } else if (mask & TST_TAINT_A) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 25;
+ } else if (mask & TST_TAINT_D) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 23;
+ } else if (mask & TST_TAINT_U) {
+ r1 = 2;
+ r2 = 6;
+ r3 = 21;
+ } else {
+ r1 = 2;
+ r2 = 6;
+ r3 = 16;
+ }
+
+ return tst_kvercmp(r1, r2, r3);
+}
+
+void tst_taint_init(unsigned int mask)
+{
+ unsigned int taint = -1;
+
+ if (mask == 0)
+ tst_brk(TBROK, "mask is not allowed to be 0");
+
+ if (tst_taint_check_kver(mask) < 0)
+ tst_res(TCONF, "Kernel is too old for requested mask");
+
+ taint_mask = mask;
+ taint = tst_taint_read();
+
+ if (taint & TST_TAINT_W) {
+ tst_res(TCONF, "Ignoring already set kernel warning taint");
+ taint_mask &= ~TST_TAINT_W;
+ }
+
+ if ((taint & taint_mask) != 0)
+ tst_brk(TBROK, "Kernel is already tainted: %u", taint);
+}
+
+
+unsigned int tst_taint_check(void)
+{
+ unsigned int taint = -1;
+
+ if (taint_mask == (unsigned int) -1)
+ tst_brk(TBROK, "need to call tst_taint_init() first");
+
+ taint = tst_taint_read();
+
+ return (taint & taint_mask);
+}
diff --git a/src/kernel/tests/lib/tst_test.c b/src/kernel/tests/lib/tst_test.c
new file mode 100644
index 0000000..135cd4e
--- /dev/null
+++ b/src/kernel/tests/lib/tst_test.c
@@ -0,0 +1,1387 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015-2016 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_device.h"
+#include "lapi/futex.h"
+#include "lapi/syscalls.h"
+#include "tst_ansi_color.h"
+#include "tst_safe_stdio.h"
+#include "tst_timer_test.h"
+#include "tst_clocks.h"
+#include "tst_timer.h"
+#include "tst_wallclock.h"
+#include "tst_sys_conf.h"
+#include "tst_kconfig.h"
+
+#include "old_resource.h"
+#include "old_device.h"
+#include "old_tmpdir.h"
+
+/*
+ * Hack to get TCID defined in newlib tests
+ */
+const char *TCID __attribute__((weak));
+
+#define LINUX_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id="
+#define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-"
+
+struct tst_test *tst_test;
+
+static const char *tid;
+static int iterations = 1;
+static float duration = -1;
+static float timeout_mul = -1;
+static pid_t main_pid, lib_pid;
+static int mntpoint_mounted;
+static int ovl_mounted;
+static struct timespec tst_start_time; /* valid only for test pid */
+
+struct results {
+ int passed;
+ int skipped;
+ int failed;
+ int warnings;
+ unsigned int timeout;
+};
+
+static struct results *results;
+
+static int ipc_fd;
+
+extern void *tst_futexes;
+extern unsigned int tst_max_futexes;
+
+#define IPC_ENV_VAR "LTP_IPC_PATH"
+
+static char ipc_path[1064];
+const char *tst_ipc_path = ipc_path;
+
+static char shm_path[1024];
+
+int TST_ERR;
+long TST_RET;
+
+static void do_cleanup(void);
+static void do_exit(int ret) __attribute__ ((noreturn));
+
+static void setup_ipc(void)
+{
+ size_t size = getpagesize();
+
+ if (access("/dev/shm", F_OK) == 0) {
+ snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d",
+ tid, getpid());
+ } else {
+ char *tmpdir;
+
+ if (!tst_tmpdir_created())
+ tst_tmpdir();
+
+ tmpdir = tst_get_tmpdir();
+ snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d",
+ tmpdir, tid, getpid());
+ free(tmpdir);
+ }
+
+ ipc_fd = open(shm_path, O_CREAT | O_EXCL | O_RDWR, 0600);
+ if (ipc_fd < 0)
+ tst_brk(TBROK | TERRNO, "open(%s)", shm_path);
+ SAFE_CHMOD(shm_path, 0666);
+
+ SAFE_FTRUNCATE(ipc_fd, size);
+
+ results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0);
+
+ /* Checkpoints needs to be accessible from processes started by exec() */
+ if (tst_test->needs_checkpoints || tst_test->child_needs_reinit) {
+ sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path);
+ putenv(ipc_path);
+ } else {
+ SAFE_UNLINK(shm_path);
+ }
+
+ SAFE_CLOSE(ipc_fd);
+
+ if (tst_test->needs_checkpoints) {
+ tst_futexes = (char*)results + sizeof(struct results);
+ tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
+ }
+}
+
+static void cleanup_ipc(void)
+{
+ size_t size = getpagesize();
+
+ if (ipc_fd > 0 && close(ipc_fd))
+ tst_res(TWARN | TERRNO, "close(ipc_fd) failed");
+
+ if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path))
+ tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path);
+
+ if (results) {
+ msync((void*)results, size, MS_SYNC);
+ munmap((void*)results, size);
+ results = NULL;
+ }
+}
+
+void tst_reinit(void)
+{
+ const char *path = getenv(IPC_ENV_VAR);
+ size_t size = getpagesize();
+ int fd;
+
+ if (!path)
+ tst_brk(TBROK, IPC_ENV_VAR" is not defined");
+
+ if (access(path, F_OK))
+ tst_brk(TBROK, "File %s does not exist!", path);
+
+ fd = SAFE_OPEN(path, O_RDWR);
+
+ results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ tst_futexes = (char*)results + sizeof(struct results);
+ tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
+
+ SAFE_CLOSE(fd);
+}
+
+static void update_results(int ttype)
+{
+ if (!results)
+ return;
+
+ switch (ttype) {
+ case TCONF:
+ tst_atomic_inc(&results->skipped);
+ break;
+ case TPASS:
+ tst_atomic_inc(&results->passed);
+ break;
+ case TWARN:
+ tst_atomic_inc(&results->warnings);
+ break;
+ case TFAIL:
+ tst_atomic_inc(&results->failed);
+ break;
+ }
+}
+
+static void print_result(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va)
+{
+ char buf[1024];
+ char *str = buf;
+ int ret, size = sizeof(buf), ssize, int_errno, buflen;
+ const char *str_errno = NULL;
+ const char *res;
+
+ switch (TTYPE_RESULT(ttype)) {
+ case TPASS:
+ res = "PASS";
+ break;
+ case TFAIL:
+ res = "FAIL";
+ break;
+ case TBROK:
+ res = "BROK";
+ break;
+ case TCONF:
+ res = "CONF";
+ break;
+ case TWARN:
+ res = "WARN";
+ break;
+ case TINFO:
+ res = "INFO";
+ break;
+ default:
+ tst_brk(TBROK, "Invalid ttype value %i", ttype);
+ abort();
+ }
+
+ if (ttype & TERRNO) {
+ str_errno = tst_strerrno(errno);
+ int_errno = errno;
+ }
+
+ if (ttype & TTERRNO) {
+ str_errno = tst_strerrno(TST_ERR);
+ int_errno = TST_ERR;
+ }
+
+ if (ttype & TRERRNO) {
+ int_errno = TST_RET < 0 ? -(int)TST_RET : (int)TST_RET;
+ str_errno = tst_strerrno(int_errno);
+ }
+
+ ret = snprintf(str, size, "%s:%i: ", file, lineno);
+ str += ret;
+ size -= ret;
+
+ if (tst_color_enabled(STDERR_FILENO))
+ ret = snprintf(str, size, "%s%s: %s", tst_ttype2color(ttype),
+ res, ANSI_COLOR_RESET);
+ else
+ ret = snprintf(str, size, "%s: ", res);
+ str += ret;
+ size -= ret;
+
+ ssize = size - 2;
+ ret = vsnprintf(str, size, fmt, va);
+ str += MIN(ret, ssize);
+ size -= MIN(ret, ssize);
+ if (ret >= ssize) {
+ tst_res_(file, lineno, TWARN,
+ "Next message is too long and truncated:");
+ } else if (str_errno) {
+ ssize = size - 2;
+ ret = snprintf(str, size, ": %s (%d)", str_errno, int_errno);
+ str += MIN(ret, ssize);
+ size -= MIN(ret, ssize);
+ if (ret >= ssize)
+ tst_res_(file, lineno, TWARN,
+ "Next message is too long and truncated:");
+ }
+
+ snprintf(str, size, "\n");
+
+ /* we might be called from signal handler, so use write() */
+ buflen = str - buf + 1;
+ str = buf;
+ while (buflen) {
+ ret = write(STDERR_FILENO, str, buflen);
+ if (ret <= 0)
+ break;
+
+ str += ret;
+ buflen -= ret;
+ }
+}
+
+void tst_vres_(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va)
+{
+ print_result(file, lineno, ttype, fmt, va);
+
+ update_results(TTYPE_RESULT(ttype));
+}
+
+void tst_vbrk_(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va);
+
+static void (*tst_brk_handler)(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va) = tst_vbrk_;
+
+static void tst_cvres(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va)
+{
+ if (TTYPE_RESULT(ttype) == TBROK) {
+ ttype &= ~TTYPE_MASK;
+ ttype |= TWARN;
+ }
+
+ print_result(file, lineno, ttype, fmt, va);
+ update_results(TTYPE_RESULT(ttype));
+}
+
+static void do_test_cleanup(void)
+{
+ tst_brk_handler = tst_cvres;
+
+ if (tst_test->cleanup)
+ tst_test->cleanup();
+
+ tst_free_all();
+
+ tst_brk_handler = tst_vbrk_;
+}
+
+void tst_vbrk_(const char *file, const int lineno, int ttype,
+ const char *fmt, va_list va)
+{
+ print_result(file, lineno, ttype, fmt, va);
+ update_results(TTYPE_RESULT(ttype));
+
+ /*
+ * The getpid implementation in some C library versions may cause cloned
+ * test threads to show the same pid as their parent when CLONE_VM is
+ * specified but CLONE_THREAD is not. Use direct syscall to avoid
+ * cleanup running in the child.
+ */
+ if (syscall(SYS_getpid) == main_pid)
+ do_test_cleanup();
+
+ if (getpid() == lib_pid)
+ do_exit(TTYPE_RESULT(ttype));
+
+ exit(TTYPE_RESULT(ttype));
+}
+
+void tst_res_(const char *file, const int lineno, int ttype,
+ const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ tst_vres_(file, lineno, ttype, fmt, va);
+ va_end(va);
+}
+
+void tst_brk_(const char *file, const int lineno, int ttype,
+ const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ tst_brk_handler(file, lineno, ttype, fmt, va);
+ va_end(va);
+}
+
+static void check_child_status(pid_t pid, int status)
+{
+ int ret;
+
+ if (WIFSIGNALED(status)) {
+ tst_brk(TBROK, "Child (%i) killed by signal %s",
+ pid, tst_strsig(WTERMSIG(status)));
+ }
+
+ if (!(WIFEXITED(status)))
+ tst_brk(TBROK, "Child (%i) exited abnormally", pid);
+
+ ret = WEXITSTATUS(status);
+ switch (ret) {
+ case TPASS:
+ break;
+ case TBROK:
+ case TCONF:
+ tst_brk(ret, "Reported by child (%i)", pid);
+ break;
+ default:
+ tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret);
+ }
+}
+
+void tst_reap_children(void)
+{
+ int status;
+ pid_t pid;
+
+ for (;;) {
+ pid = wait(&status);
+
+ if (pid > 0) {
+ check_child_status(pid, status);
+ continue;
+ }
+
+ if (errno == ECHILD)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ tst_brk(TBROK | TERRNO, "wait() failed");
+ }
+}
+
+
+pid_t safe_fork(const char *filename, unsigned int lineno)
+{
+ pid_t pid;
+
+ if (!tst_test->forks_child)
+ tst_brk(TBROK, "test.forks_child must be set!");
+
+ tst_flush();
+
+ pid = fork();
+ if (pid < 0)
+ tst_brk_(filename, lineno, TBROK | TERRNO, "fork() failed");
+
+ if (!pid)
+ atexit(tst_free_all);
+
+ return pid;
+}
+
+static struct option {
+ char *optstr;
+ char *help;
+} options[] = {
+ {"h", "-h Prints this help"},
+ {"i:", "-i n Execute test n times"},
+ {"I:", "-I x Execute test for n seconds"},
+ {"C:", "-C ARG Run child process with ARG arguments (used internally)"},
+};
+
+static void print_help(void)
+{
+ unsigned int i;
+
+ fprintf(stderr, "Options\n");
+ fprintf(stderr, "-------\n");
+
+ for (i = 0; i < ARRAY_SIZE(options); i++)
+ fprintf(stderr, "%s\n", options[i].help);
+
+ if (!tst_test->options)
+ return;
+
+ for (i = 0; tst_test->options[i].optstr; i++)
+ fprintf(stderr, "%s\n", tst_test->options[i].help);
+}
+
+static void print_test_tags(void)
+{
+ unsigned int i;
+ const struct tst_tag *tags = tst_test->tags;
+
+ if (!tags)
+ return;
+
+ printf("\nTags\n");
+ printf("----\n");
+
+ for (i = 0; tags[i].name; i++) {
+ if (!strcmp(tags[i].name, "CVE"))
+ printf(CVE_DB_URL "%s\n", tags[i].value);
+ else if (!strcmp(tags[i].name, "linux-git"))
+ printf(LINUX_GIT_URL "%s\n", tags[i].value);
+ else
+ printf("%s: %s\n", tags[i].name, tags[i].value);
+ }
+
+ printf("\n");
+}
+
+static void check_option_collision(void)
+{
+ unsigned int i, j;
+ struct tst_option *toptions = tst_test->options;
+
+ if (!toptions)
+ return;
+
+ for (i = 0; toptions[i].optstr; i++) {
+ for (j = 0; j < ARRAY_SIZE(options); j++) {
+ if (toptions[i].optstr[0] == options[j].optstr[0]) {
+ tst_brk(TBROK, "Option collision '%s'",
+ options[j].help);
+ }
+ }
+ }
+}
+
+static unsigned int count_options(void)
+{
+ unsigned int i;
+
+ if (!tst_test->options)
+ return 0;
+
+ for (i = 0; tst_test->options[i].optstr; i++);
+
+ return i;
+}
+
+static void parse_topt(unsigned int topts_len, int opt, char *optarg)
+{
+ unsigned int i;
+ struct tst_option *toptions = tst_test->options;
+
+ for (i = 0; i < topts_len; i++) {
+ if (toptions[i].optstr[0] == opt)
+ break;
+ }
+
+ if (i >= topts_len)
+ tst_brk(TBROK, "Invalid option '%c' (should not happen)", opt);
+
+ if (*toptions[i].arg)
+ tst_res(TWARN, "Option -%c passed multiple times", opt);
+
+ *(toptions[i].arg) = optarg ? optarg : "";
+}
+
+/* see self_exec.c */
+#ifdef UCLINUX
+extern char *child_args;
+#endif
+
+static void parse_opts(int argc, char *argv[])
+{
+ unsigned int i, topts_len = count_options();
+ char optstr[2 * ARRAY_SIZE(options) + 2 * topts_len];
+ int opt;
+
+ check_option_collision();
+
+ optstr[0] = 0;
+
+ for (i = 0; i < ARRAY_SIZE(options); i++)
+ strcat(optstr, options[i].optstr);
+
+ for (i = 0; i < topts_len; i++)
+ strcat(optstr, tst_test->options[i].optstr);
+
+ while ((opt = getopt(argc, argv, optstr)) > 0) {
+ switch (opt) {
+ case '?':
+ print_help();
+ tst_brk(TBROK, "Invalid option");
+ break;
+ case 'h':
+ print_help();
+ print_test_tags();
+ exit(0);
+ case 'i':
+ iterations = atoi(optarg);
+ break;
+ case 'I':
+ duration = atof(optarg);
+ break;
+ case 'C':
+#ifdef UCLINUX
+ child_args = optarg;
+#endif
+ break;
+ default:
+ parse_topt(topts_len, opt, optarg);
+ }
+ }
+
+ if (optind < argc)
+ tst_brk(TBROK, "Unexpected argument(s) '%s'...", argv[optind]);
+}
+
+int tst_parse_int(const char *str, int *val, int min, int max)
+{
+ long rval;
+
+ if (!str)
+ return 0;
+
+ int ret = tst_parse_long(str, &rval, min, max);
+
+ if (ret)
+ return ret;
+
+ *val = (int)rval;
+ return 0;
+}
+
+int tst_parse_long(const char *str, long *val, long min, long max)
+{
+ long rval;
+ char *end;
+
+ if (!str)
+ return 0;
+
+ errno = 0;
+ rval = strtol(str, &end, 10);
+
+ if (str == end || *end != '\0')
+ return EINVAL;
+
+ if (errno)
+ return errno;
+
+ if (rval > max || rval < min)
+ return ERANGE;
+
+ *val = rval;
+ return 0;
+}
+
+int tst_parse_float(const char *str, float *val, float min, float max)
+{
+ double rval;
+ char *end;
+
+ if (!str)
+ return 0;
+
+ errno = 0;
+ rval = strtod(str, &end);
+
+ if (str == end || *end != '\0')
+ return EINVAL;
+
+ if (errno)
+ return errno;
+
+ if (rval > (double)max || rval < (double)min)
+ return ERANGE;
+
+ *val = (float)rval;
+ return 0;
+}
+
+static void print_colored(const char *str)
+{
+ if (tst_color_enabled(STDOUT_FILENO))
+ printf("%s%s%s", ANSI_COLOR_YELLOW, str, ANSI_COLOR_RESET);
+ else
+ printf("%s", str);
+}
+
+static void print_failure_hints(void)
+{
+ unsigned int i;
+ const struct tst_tag *tags = tst_test->tags;
+
+ if (!tags)
+ return;
+
+ int hint_printed = 0;
+ for (i = 0; tags[i].name; i++) {
+ if (!strcmp(tags[i].name, "linux-git")) {
+ if (!hint_printed) {
+ hint_printed = 1;
+ printf("\n");
+ print_colored("HINT: ");
+ printf("You _MAY_ be missing kernel fixes, see:\n\n");
+ }
+
+ printf(LINUX_GIT_URL "%s\n", tags[i].value);
+ }
+
+ }
+
+ hint_printed = 0;
+ for (i = 0; tags[i].name; i++) {
+ if (!strcmp(tags[i].name, "CVE")) {
+ if (!hint_printed) {
+ hint_printed = 1;
+ printf("\n");
+ print_colored("HINT: ");
+ printf("You _MAY_ be vulnerable to CVE(s), see:\n\n");
+ }
+
+ printf(CVE_DB_URL "%s\n", tags[i].value);
+ }
+ }
+}
+
+static void do_exit(int ret)
+{
+ if (results) {
+ if (results->passed && ret == TCONF)
+ ret = 0;
+
+ if (results->failed) {
+ ret |= TFAIL;
+ print_failure_hints();
+ }
+
+ if (results->skipped && !results->passed)
+ ret |= TCONF;
+
+ if (results->warnings)
+ ret |= TWARN;
+
+ printf("\nSummary:\n");
+ printf("passed %d\n", results->passed);
+ printf("failed %d\n", results->failed);
+ printf("skipped %d\n", results->skipped);
+ printf("warnings %d\n", results->warnings);
+ }
+
+ do_cleanup();
+
+ exit(ret);
+}
+
+void check_kver(void)
+{
+ int v1, v2, v3;
+
+ if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) {
+ tst_res(TWARN,
+ "Invalid kernel version %s, expected %%d.%%d.%%d",
+ tst_test->min_kver);
+ }
+
+ if (tst_kvercmp(v1, v2, v3) < 0) {
+ tst_brk(TCONF, "The test requires kernel %s or newer",
+ tst_test->min_kver);
+ }
+}
+
+static int results_equal(struct results *a, struct results *b)
+{
+ if (a->passed != b->passed)
+ return 0;
+
+ if (a->failed != b->failed)
+ return 0;
+
+ if (a->skipped != b->skipped)
+ return 0;
+
+ return 1;
+}
+
+static int needs_tmpdir(void)
+{
+ return tst_test->needs_tmpdir ||
+ tst_test->needs_device ||
+ tst_test->mntpoint ||
+ tst_test->resource_files ||
+ tst_test->needs_checkpoints;
+}
+
+static void copy_resources(void)
+{
+ unsigned int i;
+
+ for (i = 0; tst_test->resource_files[i]; i++)
+ TST_RESOURCE_COPY(NULL, tst_test->resource_files[i], NULL);
+}
+
+static const char *get_tid(char *argv[])
+{
+ char *p;
+
+ if (!argv[0] || !argv[0][0]) {
+ tst_res(TINFO, "argv[0] is empty!");
+ return "ltp_empty_argv";
+ }
+
+ p = strrchr(argv[0], '/');
+ if (p)
+ return p+1;
+
+ return argv[0];
+}
+
+static struct tst_device tdev;
+struct tst_device *tst_device;
+
+static void assert_test_fn(void)
+{
+ int cnt = 0;
+
+ if (tst_test->test)
+ cnt++;
+
+ if (tst_test->test_all)
+ cnt++;
+
+ if (tst_test->sample)
+ cnt++;
+
+ if (!cnt)
+ tst_brk(TBROK, "No test function specified");
+
+ if (cnt != 1)
+ tst_brk(TBROK, "You can define only one test function");
+
+ if (tst_test->test && !tst_test->tcnt)
+ tst_brk(TBROK, "Number of tests (tcnt) must be > 0");
+
+ if (!tst_test->test && tst_test->tcnt)
+ tst_brk(TBROK, "You can define tcnt only for test()");
+}
+
+static int prepare_and_mount_ro_fs(const char *dev,
+ const char *mntpoint,
+ const char *fs_type)
+{
+ char buf[PATH_MAX];
+
+ if (mount(dev, mntpoint, fs_type, 0, NULL)) {
+ tst_res(TINFO | TERRNO, "Can't mount %s at %s (%s)",
+ dev, mntpoint, fs_type);
+ return 1;
+ }
+
+ mntpoint_mounted = 1;
+
+ snprintf(buf, sizeof(buf), "%s/dir/", mntpoint);
+ SAFE_MKDIR(buf, 0777);
+
+ snprintf(buf, sizeof(buf), "%s/file", mntpoint);
+ SAFE_FILE_PRINTF(buf, "file content");
+ SAFE_CHMOD(buf, 0777);
+
+ SAFE_MOUNT(dev, mntpoint, fs_type, MS_REMOUNT | MS_RDONLY, NULL);
+
+ return 0;
+}
+
+static void prepare_and_mount_dev_fs(const char *mntpoint)
+{
+ const char *flags[] = {"nodev", NULL};
+ int mounted_nodev;
+
+ mounted_nodev = tst_path_has_mnt_flags(NULL, flags);
+ if (mounted_nodev) {
+ tst_res(TINFO, "tmpdir isn't suitable for creating devices, "
+ "mounting tmpfs without nodev on %s", mntpoint);
+ SAFE_MOUNT(NULL, mntpoint, "tmpfs", 0, NULL);
+ mntpoint_mounted = 1;
+ }
+}
+
+static void prepare_device(void)
+{
+ if (tst_test->format_device) {
+ SAFE_MKFS(tdev.dev, tdev.fs_type, tst_test->dev_fs_opts,
+ tst_test->dev_extra_opts);
+ }
+
+ if (tst_test->needs_rofs) {
+ prepare_and_mount_ro_fs(tdev.dev, tst_test->mntpoint,
+ tdev.fs_type);
+ return;
+ }
+
+ if (tst_test->mount_device) {
+ SAFE_MOUNT(tdev.dev, tst_test->mntpoint, tdev.fs_type,
+ tst_test->mnt_flags, tst_test->mnt_data);
+ mntpoint_mounted = 1;
+ }
+}
+
+static void do_setup(int argc, char *argv[])
+{
+ if (!tst_test)
+ tst_brk(TBROK, "No tests to run");
+
+ if (tst_test->tconf_msg)
+ tst_brk(TCONF, "%s", tst_test->tconf_msg);
+
+ if (tst_test->needs_kconfigs)
+ tst_kconfig_check(tst_test->needs_kconfigs);
+
+ assert_test_fn();
+
+ tid = get_tid(argv);
+
+ if (tst_test->sample)
+ tst_test = tst_timer_test_setup(tst_test);
+
+ parse_opts(argc, argv);
+
+ if (tst_test->needs_root && geteuid() != 0)
+ tst_brk(TCONF, "Test needs to be run as root");
+
+ if (tst_test->min_kver)
+ check_kver();
+
+ if (tst_test->needs_cmds) {
+ const char *cmd;
+ char path[PATH_MAX];
+ int i;
+
+ for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i)
+ if (tst_get_path(cmd, path, sizeof(path)))
+ tst_brk(TCONF, "Couldn't find '%s' in $PATH", cmd);
+ }
+
+ if (tst_test->needs_drivers) {
+ const char *name;
+ int i;
+
+ for (i = 0; (name = tst_test->needs_drivers[i]); ++i)
+ if (tst_check_driver(name))
+ tst_brk(TCONF, "%s driver not available", name);
+ }
+
+ if (tst_test->format_device)
+ tst_test->needs_device = 1;
+
+ if (tst_test->mount_device) {
+ tst_test->needs_device = 1;
+ tst_test->format_device = 1;
+ }
+
+ if (tst_test->all_filesystems)
+ tst_test->needs_device = 1;
+
+ if (tst_test->request_hugepages)
+ tst_request_hugepages(tst_test->request_hugepages);
+
+ setup_ipc();
+
+ if (tst_test->bufs)
+ tst_buffers_alloc(tst_test->bufs);
+
+ if (needs_tmpdir() && !tst_tmpdir_created())
+ tst_tmpdir();
+
+ if (tst_test->save_restore) {
+ const char * const *name = tst_test->save_restore;
+
+ while (*name) {
+ tst_sys_conf_save(*name);
+ name++;
+ }
+ }
+
+ if (tst_test->mntpoint)
+ SAFE_MKDIR(tst_test->mntpoint, 0777);
+
+ if ((tst_test->needs_devfs || tst_test->needs_rofs ||
+ tst_test->mount_device || tst_test->all_filesystems) &&
+ !tst_test->mntpoint) {
+ tst_brk(TBROK, "tst_test->mntpoint must be set!");
+ }
+
+ if (!!tst_test->needs_rofs + !!tst_test->needs_devfs +
+ !!tst_test->needs_device > 1) {
+ tst_brk(TBROK,
+ "Two or more of needs_{rofs, devfs, device} are set");
+ }
+
+ if (tst_test->needs_devfs)
+ prepare_and_mount_dev_fs(tst_test->mntpoint);
+
+ if (tst_test->needs_rofs) {
+ /* If we failed to mount read-only tmpfs. Fallback to
+ * using a device with read-only filesystem.
+ */
+ if (prepare_and_mount_ro_fs(NULL, tst_test->mntpoint, "tmpfs")) {
+ tst_res(TINFO, "Can't mount tmpfs read-only, "
+ "falling back to block device...");
+ tst_test->needs_device = 1;
+ tst_test->format_device = 1;
+ }
+ }
+
+ if (tst_test->needs_device && !mntpoint_mounted) {
+ tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size);
+
+ if (!tdev.dev)
+ tst_brk(TCONF, "Failed to acquire device");
+
+ tst_device = &tdev;
+
+ if (tst_test->dev_fs_type)
+ tdev.fs_type = tst_test->dev_fs_type;
+ else
+ tdev.fs_type = tst_dev_fs_type();
+
+ if (!tst_test->all_filesystems)
+ prepare_device();
+ }
+
+ if (tst_test->needs_overlay && !tst_test->mount_device) {
+ tst_brk(TBROK, "tst_test->mount_device must be set");
+ }
+ if (tst_test->needs_overlay && !mntpoint_mounted) {
+ tst_brk(TBROK, "tst_test->mntpoint must be mounted");
+ }
+ if (tst_test->needs_overlay && !ovl_mounted) {
+ SAFE_MOUNT_OVERLAY();
+ ovl_mounted = 1;
+ }
+
+ if (tst_test->resource_files)
+ copy_resources();
+
+ if (tst_test->restore_wallclock)
+ tst_wallclock_save();
+
+ if (tst_test->taint_check)
+ tst_taint_init(tst_test->taint_check);
+}
+
+static void do_test_setup(void)
+{
+ main_pid = getpid();
+
+ if (tst_test->caps)
+ tst_cap_setup(tst_test->caps, TST_CAP_REQ);
+
+ if (tst_test->setup)
+ tst_test->setup();
+
+ if (main_pid != getpid())
+ tst_brk(TBROK, "Runaway child in setup()!");
+
+ if (tst_test->caps)
+ tst_cap_setup(tst_test->caps, TST_CAP_DROP);
+}
+
+static void do_cleanup(void)
+{
+ if (ovl_mounted)
+ SAFE_UMOUNT(OVL_MNT);
+
+ if (mntpoint_mounted)
+ tst_umount(tst_test->mntpoint);
+
+ if (tst_test->needs_device && tdev.dev)
+ tst_release_device(tdev.dev);
+
+ if (tst_tmpdir_created()) {
+ /* avoid munmap() on wrong pointer in tst_rmdir() */
+ tst_futexes = NULL;
+ tst_rmdir();
+ }
+
+ tst_sys_conf_restore(0);
+
+ if (tst_test->restore_wallclock)
+ tst_wallclock_restore();
+
+ cleanup_ipc();
+}
+
+static void run_tests(void)
+{
+ unsigned int i;
+ struct results saved_results;
+
+ if (!tst_test->test) {
+ saved_results = *results;
+ tst_test->test_all();
+
+ if (getpid() != main_pid) {
+ exit(0);
+ }
+
+ tst_reap_children();
+
+ if (results_equal(&saved_results, results))
+ tst_brk(TBROK, "Test haven't reported results!");
+ return;
+ }
+
+ for (i = 0; i < tst_test->tcnt; i++) {
+ saved_results = *results;
+ tst_test->test(i);
+
+ if (getpid() != main_pid) {
+ exit(0);
+ }
+
+ tst_reap_children();
+
+ if (results_equal(&saved_results, results))
+ tst_brk(TBROK, "Test %i haven't reported results!", i);
+ }
+}
+
+static unsigned long long get_time_ms(void)
+{
+ struct timespec ts;
+
+ if (tst_clock_gettime(CLOCK_MONOTONIC, &ts))
+ tst_brk(TBROK | TERRNO, "tst_clock_gettime()");
+
+ return tst_timespec_to_ms(ts);
+}
+
+static void add_paths(void)
+{
+ char *old_path = getenv("PATH");
+ const char *start_dir;
+ char *new_path;
+
+ start_dir = tst_get_startwd();
+
+ if (old_path)
+ SAFE_ASPRINTF(&new_path, "%s::%s", old_path, start_dir);
+ else
+ SAFE_ASPRINTF(&new_path, "::%s", start_dir);
+
+ SAFE_SETENV("PATH", new_path, 1);
+ free(new_path);
+}
+
+static void heartbeat(void)
+{
+ if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time))
+ tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
+
+ kill(getppid(), SIGUSR1);
+}
+
+static void testrun(void)
+{
+ unsigned int i = 0;
+ unsigned long long stop_time = 0;
+ int cont = 1;
+
+ heartbeat();
+ add_paths();
+ do_test_setup();
+
+ if (duration > 0)
+ stop_time = get_time_ms() + (unsigned long long)(duration * 1000);
+
+ for (;;) {
+ cont = 0;
+
+ if (i < (unsigned int)iterations) {
+ i++;
+ cont = 1;
+ }
+
+ if (stop_time && get_time_ms() < stop_time)
+ cont = 1;
+
+ if (!cont)
+ break;
+
+ run_tests();
+ heartbeat();
+ }
+
+ do_test_cleanup();
+ exit(0);
+}
+
+static pid_t test_pid;
+
+
+static volatile sig_atomic_t sigkill_retries;
+
+#define WRITE_MSG(msg) do { \
+ if (write(2, msg, sizeof(msg) - 1)) { \
+ /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */ \
+ } \
+} while (0)
+
+static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED)
+{
+ WRITE_MSG("Test timeouted, sending SIGKILL!\n");
+ kill(-test_pid, SIGKILL);
+ alarm(5);
+
+ if (++sigkill_retries > 10) {
+ WRITE_MSG("Cannot kill test processes!\n");
+ WRITE_MSG("Congratulation, likely test hit a kernel bug.\n");
+ WRITE_MSG("Exitting uncleanly...\n");
+ _exit(TFAIL);
+ }
+}
+
+static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED)
+{
+ alarm(results->timeout);
+ sigkill_retries = 0;
+}
+
+static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED)
+{
+ if (test_pid > 0) {
+ WRITE_MSG("Sending SIGKILL to test process...\n");
+ kill(-test_pid, SIGKILL);
+ }
+}
+
+unsigned int tst_timeout_remaining(void)
+{
+ static struct timespec now;
+ unsigned int elapsed;
+
+ if (tst_clock_gettime(CLOCK_MONOTONIC, &now))
+ tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
+
+ elapsed = (tst_timespec_diff_ms(now, tst_start_time) + 500) / 1000;
+ if (results->timeout > elapsed)
+ return results->timeout - elapsed;
+
+ return 0;
+}
+
+unsigned int tst_multiply_timeout(unsigned int timeout)
+{
+ char *mul;
+ int ret;
+
+ if (timeout_mul == -1) {
+ mul = getenv("LTP_TIMEOUT_MUL");
+ if (mul) {
+ if ((ret = tst_parse_float(mul, &timeout_mul, 1, 10000))) {
+ tst_brk(TBROK, "Failed to parse LTP_TIMEOUT_MUL: %s",
+ tst_strerrno(ret));
+ }
+ } else {
+ timeout_mul = 1;
+ }
+ }
+ if (timeout_mul < 1)
+ tst_brk(TBROK, "LTP_TIMEOUT_MUL must to be int >= 1! (%.2f)",
+ timeout_mul);
+
+ if (timeout < 1)
+ tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout);
+
+ return timeout * timeout_mul;
+}
+
+void tst_set_timeout(int timeout)
+{
+ if (timeout == -1) {
+ tst_res(TINFO, "Timeout per run is disabled");
+ return;
+ }
+
+ if (timeout < 1)
+ tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout);
+
+ results->timeout = tst_multiply_timeout(timeout);
+
+ tst_res(TINFO, "Timeout per run is %uh %02um %02us",
+ results->timeout/3600, (results->timeout%3600)/60,
+ results->timeout % 60);
+
+ if (getpid() == lib_pid)
+ alarm(results->timeout);
+ else
+ heartbeat();
+}
+
+static int fork_testrun(void)
+{
+ int status;
+
+ if (tst_test->timeout)
+ tst_set_timeout(tst_test->timeout);
+ else
+ tst_set_timeout(300);
+
+ SAFE_SIGNAL(SIGINT, sigint_handler);
+
+ test_pid = fork();
+ if (test_pid < 0)
+ tst_brk(TBROK | TERRNO, "fork()");
+
+ if (!test_pid) {
+ SAFE_SIGNAL(SIGALRM, SIG_DFL);
+ SAFE_SIGNAL(SIGUSR1, SIG_DFL);
+ SAFE_SIGNAL(SIGINT, SIG_DFL);
+ SAFE_SETPGID(0, 0);
+ testrun();
+ }
+
+ SAFE_WAITPID(test_pid, &status, 0);
+ alarm(0);
+ SAFE_SIGNAL(SIGINT, SIG_DFL);
+
+ if (tst_test->taint_check && tst_taint_check()) {
+ tst_res(TFAIL, "Kernel is now tainted.");
+ return TFAIL;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status))
+ return WEXITSTATUS(status);
+
+ if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
+ tst_res(TINFO, "If you are running on slow machine, "
+ "try exporting LTP_TIMEOUT_MUL > 1");
+ tst_brk(TBROK, "Test killed! (timeout?)");
+ }
+
+ if (WIFSIGNALED(status))
+ tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status)));
+
+ return 0;
+}
+
+static int run_tcases_per_fs(void)
+{
+ int ret = 0;
+ unsigned int i;
+ const char *const *filesystems = tst_get_supported_fs_types(tst_test->dev_fs_flags);
+
+ if (!filesystems[0])
+ tst_brk(TCONF, "There are no supported filesystems");
+
+ for (i = 0; filesystems[i]; i++) {
+
+ tst_res(TINFO, "Testing on %s", filesystems[i]);
+ tdev.fs_type = filesystems[i];
+
+ prepare_device();
+
+ ret = fork_testrun();
+
+ if (mntpoint_mounted) {
+ tst_umount(tst_test->mntpoint);
+ mntpoint_mounted = 0;
+ }
+
+ if (ret == TCONF)
+ continue;
+
+ if (ret == 0)
+ continue;
+
+ do_exit(ret);
+ }
+
+ return ret;
+}
+
+unsigned int tst_variant;
+
+void tst_run_tcases(int argc, char *argv[], struct tst_test *self)
+{
+ int ret = 0;
+ unsigned int test_variants = 1;
+
+ lib_pid = getpid();
+ tst_test = self;
+
+ do_setup(argc, argv);
+
+ TCID = tid;
+
+ SAFE_SIGNAL(SIGALRM, alarm_handler);
+ SAFE_SIGNAL(SIGUSR1, heartbeat_handler);
+
+ if (tst_test->test_variants)
+ test_variants = tst_test->test_variants;
+
+ for (tst_variant = 0; tst_variant < test_variants; tst_variant++) {
+ if (tst_test->all_filesystems)
+ ret |= run_tcases_per_fs();
+ else
+ ret |= fork_testrun();
+
+ if (ret & ~(TCONF))
+ goto exit;
+ }
+
+exit:
+ do_exit(ret);
+}
+
+
+void tst_flush(void)
+{
+ int rval;
+
+ rval = fflush(stderr);
+ if (rval != 0)
+ tst_brk(TBROK | TERRNO, "fflush(stderr) failed");
+
+ rval = fflush(stdout);
+ if (rval != 0)
+ tst_brk(TBROK | TERRNO, "fflush(stdout) failed");
+
+}
diff --git a/src/kernel/tests/lib/tst_timer.c b/src/kernel/tests/lib/tst_timer.c
new file mode 100644
index 0000000..62d8f90
--- /dev/null
+++ b/src/kernel/tests/lib/tst_timer.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <errno.h>
+
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_clocks.h"
+#include "lapi/posix_clocks.h"
+
+static struct timespec start_time, stop_time;
+static clockid_t clock_id;
+
+void tst_timer_check(clockid_t clk_id)
+{
+ if (tst_clock_gettime(clk_id, &start_time)) {
+ if (errno == EINVAL) {
+ tst_brk(TCONF,
+ "Clock id %s(%u) not supported by kernel",
+ tst_clock_name(clk_id), clk_id);
+ return;
+ }
+
+ tst_brk(TBROK | TERRNO, "tst_clock_gettime() failed");
+ }
+}
+
+void tst_timer_start(clockid_t clk_id)
+{
+ clock_id = clk_id;
+
+ if (tst_clock_gettime(clock_id, &start_time))
+ tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
+}
+
+int tst_timer_expired_ms(long long ms)
+{
+ struct timespec cur_time;
+
+ if (tst_clock_gettime(clock_id, &cur_time))
+ tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
+
+ return tst_timespec_diff_ms(cur_time, start_time) >= ms;
+}
+
+void tst_timer_stop(void)
+{
+ if (tst_clock_gettime(clock_id, &stop_time))
+ tst_res(TWARN | TERRNO, "tst_clock_gettime() failed");
+}
+
+struct timespec tst_timer_elapsed(void)
+{
+ return tst_timespec_diff(stop_time, start_time);
+}
diff --git a/src/kernel/tests/lib/tst_timer_test.c b/src/kernel/tests/lib/tst_timer_test.c
new file mode 100644
index 0000000..196c512
--- /dev/null
+++ b/src/kernel/tests/lib/tst_timer_test.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <sys/prctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_clocks.h"
+#include "tst_timer_test.h"
+
+#define MAX_SAMPLES 500
+
+static const char *scall;
+static void (*setup)(void);
+static void (*cleanup)(void);
+static int (*sample)(int clk_id, long long usec);
+static struct tst_test *test;
+
+static long long *samples;
+static unsigned int cur_sample;
+static unsigned int monotonic_resolution;
+static unsigned int timerslack;
+static int virt_env;
+
+static char *print_frequency_plot;
+static char *file_name;
+static char *str_sleep_time;
+static char *str_sample_cnt;
+static int sleep_time = -1;
+static int sample_cnt;
+
+static void print_line(char c, int len)
+{
+ while (len-- > 0)
+ fputc(c, stderr);
+}
+
+static unsigned int ceilu(float f)
+{
+ if (f - (int)f > 0)
+ return (unsigned int)f + 1;
+
+ return (unsigned int)f;
+}
+
+static unsigned int flooru(float f)
+{
+ return (unsigned int)f;
+}
+
+static float bucket_len(unsigned int bucket, unsigned int max_bucket,
+ unsigned int cols)
+{
+ return 1.00 * bucket * cols / max_bucket;
+}
+
+static const char *table_heading = " Time: us ";
+
+/*
+ * Line Header: '10023 | '
+ */
+static unsigned int header_len(long long max_sample)
+{
+ unsigned int l = 1;
+
+ while (max_sample/=10)
+ l++;
+
+ return MAX(strlen(table_heading) + 2, l + 3);
+}
+
+static void frequency_plot(void)
+{
+ unsigned int cols = 80;
+ unsigned int rows = 20;
+ unsigned int i, buckets[rows];
+ long long max_sample = samples[0];
+ long long min_sample = samples[cur_sample-1];
+ unsigned int line_header_len = header_len(max_sample);
+ unsigned int plot_line_len = cols - line_header_len;
+ unsigned int bucket_size;
+
+ memset(buckets, 0, sizeof(buckets));
+
+ /*
+ * We work with discrete data buckets smaller than 1 does not make
+ * sense as well as it's a good idea to keep buckets integer sized
+ * to avoid scaling artifacts.
+ */
+ bucket_size = MAX(1u, ceilu(1.00 * (max_sample - min_sample)/(rows-1)));
+
+ for (i = 0; i < cur_sample; i++) {
+ unsigned int bucket;
+ bucket = flooru(1.00 * (samples[i] - min_sample)/bucket_size);
+ buckets[bucket]++;
+ }
+
+ unsigned int max_bucket = buckets[0];
+ for (i = 1; i < rows; i++)
+ max_bucket = MAX(max_bucket, buckets[i]);
+
+ fprintf(stderr, "\n%*s| Frequency\n", line_header_len - 2, table_heading);
+
+ print_line('-', cols);
+ fputc('\n', stderr);
+
+ unsigned int l, r;
+
+ for (l = 0; l < rows; l++) {
+ if (buckets[l])
+ break;
+ }
+
+ for (r = rows-1; r > l; r--) {
+ if (buckets[r])
+ break;
+ }
+
+ for (i = l; i <= r; i++) {
+ float len = bucket_len(buckets[i], max_bucket, plot_line_len);
+
+ fprintf(stderr, "%*lli | ",
+ line_header_len - 3, min_sample + bucket_size*i);
+ print_line('*', len);
+
+ if ((len - (int)len) >= 0.5)
+ fputc('+', stderr);
+ else if ((len - (int)len) >= 0.25)
+ fputc('-', stderr);
+ else if (len < 0.25 && buckets[i])
+ fputc('.', stderr);
+
+ fputc('\n', stderr);
+ }
+
+ print_line('-', cols);
+ fputc('\n', stderr);
+
+ float scale = 1.00 * plot_line_len / max_bucket;
+
+ fprintf(stderr,
+ "%*uus | 1 sample = %.5f '*', %.5f '+', %.5f '-', non-zero '.'\n",
+ line_header_len - 5, bucket_size, scale, scale * 2, scale * 4);
+
+ fputc('\n', stderr);
+}
+
+void tst_timer_sample(void)
+{
+ samples[cur_sample++] = tst_timer_elapsed_us();
+}
+
+static int cmp(const void *a, const void *b)
+{
+ const long long *aa = a, *bb = b;
+
+ return (*bb - *aa);
+}
+
+/*
+ * The threshold per one syscall is computed as a sum of:
+ *
+ * 400 us - accomodates for context switches, process
+ * migrations between CPUs on SMP, etc.
+ * 2*monotonic_resolution - accomodates for granurality of the CLOCK_MONOTONIC
+ * slack_per_scall - max of 0.1% of the sleep capped on 100ms or
+ * current->timer_slack_ns, which is slack allowed
+ * in kernel
+ *
+ * The formula for slack_per_scall applies to select() and *poll*() syscalls,
+ * the futex and *nanosleep() use only the timer_slack_ns, so we are a bit
+ * less strict here that we could be for these two for longer sleep times...
+ *
+ * We also allow for outliners, i.e. add some number to the threshold in case
+ * that the number of iteration is small. For large enoung number of iterations
+ * outliners are discarded and averaged out.
+ */
+static long long compute_threshold(long long requested_us,
+ unsigned int nsamples)
+{
+ unsigned int slack_per_scall = MIN(100000, requested_us / 1000);
+
+ slack_per_scall = MAX(slack_per_scall, timerslack);
+
+ return (400 + 2 * monotonic_resolution + slack_per_scall) * nsamples
+ + 3000/nsamples;
+}
+
+/*
+ * Returns number of samples to discard.
+ *
+ * We set it to either at least 1 if number of samples > 1 or 5%.
+ */
+static unsigned int compute_discard(unsigned int nsamples)
+{
+ if (nsamples == 1)
+ return 0;
+
+ return MAX(1u, nsamples / 20);
+}
+
+static void write_to_file(void)
+{
+ unsigned int i;
+ FILE *f;
+
+ if (!file_name)
+ return;
+
+ f = fopen(file_name, "w");
+
+ if (!f) {
+ tst_res(TWARN | TERRNO,
+ "Failed to open '%s'", file_name);
+ return;
+ }
+
+ for (i = 0; i < cur_sample; i++)
+ fprintf(f, "%lli\n", samples[i]);
+
+ if (fclose(f)) {
+ tst_res(TWARN | TERRNO,
+ "Failed to close file '%s'", file_name);
+ }
+}
+
+
+/*
+ * Timer testing function.
+ *
+ * What we do here is:
+ *
+ * * Take nsamples measurements of the timer function, the function
+ * to be sampled is defined in the the actual test.
+ *
+ * * We sort the array of samples, then:
+ *
+ * - look for outliners which are samples where the sleep time has exceeded
+ * requested sleep time by an order of magnitude and, at the same time, are
+ * greater than clock resolution multiplied by three.
+ *
+ * - check for samples where the call has woken up too early which is a plain
+ * old bug
+ *
+ * - then we compute truncated mean and compare that with the requested sleep
+ * time increased by a threshold
+ */
+void do_timer_test(long long usec, unsigned int nsamples)
+{
+ long long trunc_mean, median;
+ unsigned int discard = compute_discard(nsamples);
+ unsigned int keep_samples = nsamples - discard;
+ long long threshold = compute_threshold(usec, keep_samples);
+ int i;
+ int failed = 0;
+
+ tst_res(TINFO,
+ "%s sleeping for %llius %u iterations, threshold %.2fus",
+ scall, usec, nsamples, 1.00 * threshold / (keep_samples));
+
+ cur_sample = 0;
+ for (i = 0; i < (int)nsamples; i++) {
+ if (sample(CLOCK_MONOTONIC, usec)) {
+ tst_res(TINFO, "sampling function failed, exitting");
+ return;
+ }
+ }
+
+ qsort(samples, nsamples, sizeof(samples[0]), cmp);
+
+ write_to_file();
+
+ for (i = 0; samples[i] > 10 * usec && i < (int)nsamples; i++) {
+ if (samples[i] <= 3 * monotonic_resolution)
+ break;
+ }
+
+ if (i > 0) {
+ tst_res(TINFO, "Found %i outliners in [%lli,%lli] range",
+ i, samples[0], samples[i-1]);
+ }
+
+ for (i = nsamples - 1; samples[i] < usec && i > -1; i--);
+
+ if (i < (int)nsamples - 1) {
+ tst_res(TFAIL, "%s woken up early %u times range: [%lli,%lli]",
+ scall, nsamples - 1 - i,
+ samples[i+1], samples[nsamples-1]);
+ failed = 1;
+ }
+
+ median = samples[nsamples/2];
+
+ trunc_mean = 0;
+
+ for (i = discard; i < (int)nsamples; i++)
+ trunc_mean += samples[i];
+
+ tst_res(TINFO,
+ "min %llius, max %llius, median %llius, trunc mean %.2fus (discarded %u)",
+ samples[nsamples-1], samples[0], median,
+ 1.00 * trunc_mean / keep_samples, discard);
+
+ if (virt_env) {
+ tst_res(TINFO,
+ "Virtualisation detected, skipping oversleep checks");
+ } else if (trunc_mean > (nsamples - discard) * usec + threshold) {
+ tst_res(TFAIL, "%s slept for too long", scall);
+
+ if (!print_frequency_plot)
+ frequency_plot();
+
+ failed = 1;
+ }
+
+ if (print_frequency_plot)
+ frequency_plot();
+
+ if (!failed)
+ tst_res(TPASS, "Measured times are within thresholds");
+}
+
+static void parse_timer_opts(void);
+
+static int set_latency(void)
+{
+ int fd, latency = 0;
+
+ fd = open("/dev/cpu_dma_latency", O_WRONLY);
+ if (fd < 0)
+ return fd;
+
+ return write(fd, &latency, sizeof(latency));
+}
+
+static void timer_setup(void)
+{
+ struct timespec t;
+ int ret;
+
+ if (setup)
+ setup();
+
+ /*
+ * Running tests in VM may cause timing issues, disable upper bound
+ * checks if any hypervisor is detected.
+ */
+ virt_env = tst_is_virt(VIRT_ANY);
+ tst_clock_getres(CLOCK_MONOTONIC, &t);
+
+ tst_res(TINFO, "CLOCK_MONOTONIC resolution %lins", (long)t.tv_nsec);
+
+ monotonic_resolution = t.tv_nsec / 1000;
+ timerslack = 50;
+
+#ifdef PR_GET_TIMERSLACK
+ ret = prctl(PR_GET_TIMERSLACK);
+ if (ret < 0) {
+ tst_res(TINFO, "prctl(PR_GET_TIMERSLACK) = -1, using %uus",
+ timerslack);
+ } else {
+ timerslack = ret / 1000;
+ tst_res(TINFO, "prctl(PR_GET_TIMERSLACK) = %ius", timerslack);
+ }
+#else
+ tst_res(TINFO, "PR_GET_TIMERSLACK not defined, using %uus",
+ timerslack);
+#endif /* PR_GET_TIMERSLACK */
+ parse_timer_opts();
+
+ samples = SAFE_MALLOC(sizeof(long long) * MAX(MAX_SAMPLES, sample_cnt));
+ if (set_latency() < 0)
+ tst_res(TINFO, "Failed to set zero latency constraint: %m");
+}
+
+static void timer_cleanup(void)
+{
+ free(samples);
+
+ if (cleanup)
+ cleanup();
+}
+
+static struct tst_timer_tcase {
+ long long usec;
+ unsigned int samples;
+} tcases[] = {
+ {1000, 500},
+ {2000, 500},
+ {5000, 300},
+ {10000, 100},
+ {25000, 50},
+ {100000, 10},
+ {1000000, 2},
+};
+
+static void timer_test_fn(unsigned int n)
+{
+ do_timer_test(tcases[n].usec, tcases[n].samples);
+}
+
+static void single_timer_test(void)
+{
+ do_timer_test(sleep_time, sample_cnt);
+}
+
+static struct tst_option options[] = {
+ {"p", &print_frequency_plot, "-p Print frequency plot"},
+ {"s:", &str_sleep_time, "-s us Sleep time"},
+ {"n:", &str_sample_cnt, "-n uint Number of samples to take"},
+ {"f:", &file_name, "-f fname Write measured samples into a file"},
+ {NULL, NULL, NULL}
+};
+
+static void parse_timer_opts(void)
+{
+ if (str_sleep_time) {
+ if (tst_parse_int(str_sleep_time, &sleep_time, 0, INT_MAX)) {
+ tst_brk(TBROK,
+ "Invalid sleep time '%s'", str_sleep_time);
+ }
+ }
+
+ if (str_sample_cnt) {
+ if (tst_parse_int(str_sample_cnt, &sample_cnt, 1, INT_MAX)) {
+ tst_brk(TBROK,
+ "Invalid sample count '%s'", str_sample_cnt);
+ }
+ }
+
+ if (str_sleep_time || str_sample_cnt) {
+ if (sleep_time < 0)
+ sleep_time = 10000;
+
+ if (!sample_cnt)
+ sample_cnt = 500;
+
+ long long timeout = sleep_time * sample_cnt / 1000000;
+
+ tst_set_timeout(timeout + timeout/10);
+
+ test->test_all = single_timer_test;
+ test->test = NULL;
+ test->tcnt = 0;
+ }
+}
+
+struct tst_test *tst_timer_test_setup(struct tst_test *timer_test)
+{
+ setup = timer_test->setup;
+ cleanup = timer_test->cleanup;
+ scall = timer_test->scall;
+ sample = timer_test->sample;
+
+ timer_test->scall = NULL;
+ timer_test->setup = timer_setup;
+ timer_test->cleanup = timer_cleanup;
+ timer_test->test = timer_test_fn;
+ timer_test->tcnt = ARRAY_SIZE(tcases);
+ timer_test->sample = NULL;
+ timer_test->options = options;
+
+ test = timer_test;
+
+ return timer_test;
+}
diff --git a/src/kernel/tests/lib/tst_tmpdir.c b/src/kernel/tests/lib/tst_tmpdir.c
new file mode 100644
index 0000000..0c39eb8
--- /dev/null
+++ b/src/kernel/tests/lib/tst_tmpdir.c
@@ -0,0 +1,347 @@
+/**********************************************************
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ *********************************************************/
+
+/**********************************************************
+ *
+ * OS Testing - Silicon Graphics, Inc.
+ *
+ * FUNCTION NAME : tst_tmpdir, tst_rmdir
+ *
+ * FUNCTION TITLE : Create/remove a testing temp dir
+ *
+ * SYNOPSIS:
+ * void tst_tmpdir();
+ * void tst_rmdir();
+ *
+ * AUTHOR : Dave Fenner
+ *
+ * INITIAL RELEASE : UNICOS 8.0
+ *
+ * DESCRIPTION
+ * tst_tmpdir() is used to create a unique, temporary testing
+ * directory, and make it the current working directory.
+ * tst_rmdir() is used to remove the directory created by
+ * tst_tmpdir().
+ *
+ * RETURN VALUE
+ * Neither tst_tmpdir() or tst_rmdir() has a return value.
+ *
+ *********************************************************/
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include "test.h"
+#include "safe_macros.h"
+#include "ltp_priv.h"
+#include "lapi/futex.h"
+
+/*
+ * Define some useful macros.
+ */
+#define DIR_MODE (S_IRWXU|S_IRWXG|S_IRWXO)
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/*
+ * Define global variables.
+ */
+extern char *TCID; /* defined/initialized in main() */
+static char *TESTDIR = NULL; /* the directory created */
+
+static char test_start_work_dir[PATH_MAX];
+
+/* lib/tst_checkpoint.c */
+extern futex_t *tst_futexes;
+
+static int rmobj(const char *obj, char **errmsg);
+
+int tst_tmpdir_created(void)
+{
+ return TESTDIR != NULL;
+}
+
+char *tst_get_tmpdir(void)
+{
+ if (TESTDIR == NULL) {
+ tst_brkm(TBROK, NULL, "you must call tst_tmpdir() first");
+ return NULL;
+ }
+
+ return strdup(TESTDIR);
+}
+
+const char *tst_get_startwd(void)
+{
+ return test_start_work_dir;
+}
+
+static int purge_dir(const char *path, char **errptr)
+{
+ int ret_val = 0;
+ DIR *dir;
+ struct dirent *dir_ent;
+ char dirobj[PATH_MAX];
+ static char err_msg[PATH_MAX + 1280];
+
+ /* Do NOT perform the request if the directory is "/" */
+ if (!strcmp(path, "/")) {
+ if (errptr) {
+ strcpy(err_msg, "Cannot purge system root directory");
+ *errptr = err_msg;
+ }
+
+ return -1;
+ }
+
+ errno = 0;
+
+ /* Open the directory to get access to what is in it */
+ if (!(dir = opendir(path))) {
+ if (errptr) {
+ sprintf(err_msg,
+ "Cannot open directory %s; errno=%d: %s",
+ path, errno, tst_strerrno(errno));
+ *errptr = err_msg;
+ }
+ return -1;
+ }
+
+ /* Loop through the entries in the directory, removing each one */
+ for (dir_ent = readdir(dir); dir_ent; dir_ent = readdir(dir)) {
+ /* Don't remove "." or ".." */
+ if (!strcmp(dir_ent->d_name, ".")
+ || !strcmp(dir_ent->d_name, ".."))
+ continue;
+
+ /* Recursively remove the current entry */
+ sprintf(dirobj, "%s/%s", path, dir_ent->d_name);
+ if (rmobj(dirobj, errptr) != 0)
+ ret_val = -1;
+ }
+
+ closedir(dir);
+ return ret_val;
+}
+
+static int rmobj(const char *obj, char **errmsg)
+{
+ int ret_val = 0;
+ struct stat statbuf;
+ static char err_msg[PATH_MAX + 1280];
+ int fd;
+
+ fd = open(obj, O_DIRECTORY | O_NOFOLLOW);
+ if (fd >= 0) {
+ close(fd);
+ ret_val = purge_dir(obj, errmsg);
+
+ /* If there were problems removing an entry, don't attempt to
+ remove the directory itself */
+ if (ret_val == -1)
+ return -1;
+
+ /* Get the link count, now that all the entries have been removed */
+ if (lstat(obj, &statbuf) < 0) {
+ if (errmsg != NULL) {
+ sprintf(err_msg,
+ "lstat(%s) failed; errno=%d: %s", obj,
+ errno, tst_strerrno(errno));
+ *errmsg = err_msg;
+ }
+ return -1;
+ }
+
+ /* Remove the directory itself */
+ if (statbuf.st_nlink >= 3) {
+ /* The directory is linked; unlink() must be used */
+ if (unlink(obj) < 0) {
+ if (errmsg != NULL) {
+ sprintf(err_msg,
+ "unlink(%s) failed; errno=%d: %s",
+ obj, errno, tst_strerrno(errno));
+ *errmsg = err_msg;
+ }
+ return -1;
+ }
+ } else {
+ /* The directory is not linked; remove() can be used */
+ if (remove(obj) < 0) {
+ if (errmsg != NULL) {
+ sprintf(err_msg,
+ "remove(%s) failed; errno=%d: %s",
+ obj, errno, tst_strerrno(errno));
+ *errmsg = err_msg;
+ }
+ return -1;
+ }
+ }
+ } else {
+ if (unlink(obj) < 0) {
+ if (errmsg != NULL) {
+ sprintf(err_msg,
+ "unlink(%s) failed; errno=%d: %s", obj,
+ errno, tst_strerrno(errno));
+ *errmsg = err_msg;
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void tst_tmpdir(void)
+{
+ char template[PATH_MAX];
+ char *env_tmpdir;
+ char *errmsg, *c;
+
+ /*
+ * Create a template for the temporary directory. Use the
+ * environment variable TMPDIR if it is available, otherwise
+ * use our default TEMPDIR.
+ */
+ env_tmpdir = getenv("TMPDIR");
+ if (env_tmpdir) {
+ c = strchr(env_tmpdir, '/');
+ /*
+ * Now we force environment variable TMPDIR to be an absolute
+ * pathname, which dose not make much sense, but it will
+ * greatly simplify code in tst_rmdir().
+ */
+ if (c != env_tmpdir) {
+ tst_brkm(TBROK, NULL, "You must specify an absolute "
+ "pathname for environment variable TMPDIR");
+ return;
+ }
+ snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", env_tmpdir, TCID);
+ } else {
+ snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", TEMPDIR, TCID);
+ }
+
+ /* Make the temporary directory in one shot using mkdtemp. */
+ if (mkdtemp(template) == NULL) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s: mkdtemp(%s) failed", __func__, template);
+ return;
+ }
+
+ if ((TESTDIR = strdup(template)) == NULL) {
+ tst_brkm(TBROK | TERRNO, NULL,
+ "%s: strdup(%s) failed", __func__, template);
+ return;
+ }
+
+ SAFE_CHOWN(NULL, TESTDIR, -1, getgid());
+
+ SAFE_CHMOD(NULL, TESTDIR, DIR_MODE);
+
+ if (getcwd(test_start_work_dir, sizeof(test_start_work_dir)) == NULL) {
+ tst_resm(TINFO, "Failed to record test working dir");
+ test_start_work_dir[0] = '\0';
+ }
+
+ /*
+ * Change to the temporary directory. If the chdir() fails, issue
+ * TBROK messages for all test cases, attempt to remove the
+ * directory (if it was created), and exit. If the removal also
+ * fails, also issue a TWARN message.
+ */
+ if (chdir(TESTDIR) == -1) {
+ tst_resm(TERRNO, "%s: chdir(%s) failed", __func__, TESTDIR);
+
+ /* Try to remove the directory */
+ if (rmobj(TESTDIR, &errmsg) == -1) {
+ tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
+ __func__, TESTDIR, errmsg);
+ }
+
+ tst_exit();
+ }
+}
+
+void tst_rmdir(void)
+{
+ char *errmsg;
+
+ /*
+ * Check that TESTDIR is not NULL.
+ */
+ if (TESTDIR == NULL) {
+ tst_resm(TWARN,
+ "%s: TESTDIR was NULL; no removal attempted",
+ __func__);
+ return;
+ }
+
+ /*
+ * Unmap the backend file.
+ * This is needed to overcome the NFS "silly rename" feature.
+ */
+ if (tst_futexes) {
+ msync((void *)tst_futexes, getpagesize(), MS_SYNC);
+ munmap((void *)tst_futexes, getpagesize());
+ }
+
+ /*
+ * Attempt to remove the "TESTDIR" directory, using rmobj().
+ */
+ if (rmobj(TESTDIR, &errmsg) == -1) {
+ tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
+ __func__, TESTDIR, errmsg);
+ }
+}
+
+void tst_purge_dir(const char *path)
+{
+ char *err;
+
+ if (purge_dir(path, &err))
+ tst_brkm(TBROK, NULL, "%s: %s", __func__, err);
+}
diff --git a/src/kernel/tests/lib/tst_virt.c b/src/kernel/tests/lib/tst_virt.c
new file mode 100644
index 0000000..53d33e6
--- /dev/null
+++ b/src/kernel/tests/lib/tst_virt.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 Linux Test Project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it
+ * is free of the rightful claim of any third person regarding
+ * infringement or the like. Any license provided herein, whether
+ * implied or otherwise, applies only to this software file. Patent
+ * licenses, if any, provided herein do not apply to combinations of
+ * this program with other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <unistd.h>
+#include "test.h"
+#include "safe_macros.h"
+
+static int is_kvm(void)
+{
+ FILE *cpuinfo;
+ char line[64];
+ int found;
+
+ /* this doesn't work with custom -cpu values, since there's
+ * no easy, reasonable or reliable way to work around those */
+ cpuinfo = SAFE_FOPEN(NULL, "/proc/cpuinfo", "r");
+ found = 0;
+ while (fgets(line, sizeof(line), cpuinfo) != NULL) {
+ if (strstr(line, "QEMU Virtual CPU")) {
+ found = 1;
+ break;
+ }
+ }
+
+ SAFE_FCLOSE(NULL, cpuinfo);
+ return found;
+}
+
+static int is_xen(void)
+{
+ char hypervisor_type[4];
+
+ if (access("/proc/xen", F_OK) == 0)
+ return 1;
+
+ if (access("/sys/hypervisor/type", F_OK) == 0) {
+ SAFE_FILE_SCANF(NULL, "/sys/hypervisor/type", "%3s",
+ hypervisor_type);
+ return strncmp("xen", hypervisor_type,
+ sizeof(hypervisor_type)) == 0;
+ }
+
+ return 0;
+}
+
+static int try_systemd_detect_virt(void)
+{
+ FILE *f;
+ char virt_type[64];
+ int ret;
+
+ /* See tst_cmd.c */
+ void *old_handler = signal(SIGCHLD, SIG_DFL);
+
+ f = popen("systemd-detect-virt", "r");
+ if (!f) {
+ signal(SIGCHLD, old_handler);
+ return 0;
+ }
+
+ if (!fgets(virt_type, sizeof(virt_type), f))
+ virt_type[0] = '\0';
+
+ ret = pclose(f);
+
+ signal(SIGCHLD, old_handler);
+
+ /*
+ * systemd-detect-virt not found by shell or no virtualization detected
+ * (systemd-detect-virt returns non-zero)
+ */
+ if (ret < 0 || (WIFEXITED(ret) && WEXITSTATUS(ret) == 127))
+ return -1;
+
+ if (ret)
+ return 0;
+
+ if (!strncmp("kvm", virt_type, 3))
+ return VIRT_KVM;
+
+ if (!strncmp("xen", virt_type, 3))
+ return VIRT_XEN;
+
+ return VIRT_OTHER;
+}
+
+int tst_is_virt(int virt_type)
+{
+ int ret = try_systemd_detect_virt();
+
+ if (ret >= 0) {
+ if (virt_type == VIRT_ANY)
+ return ret != 0;
+ else
+ return ret == virt_type;
+ }
+
+ switch (virt_type) {
+ case VIRT_ANY:
+ return is_xen() || is_kvm();
+ case VIRT_XEN:
+ return is_xen();
+ case VIRT_KVM:
+ return is_kvm();
+ case VIRT_OTHER:
+ return 0;
+ }
+
+ tst_brkm(TBROK, NULL, "invalid virt_type flag: %d", virt_type);
+ return -1;
+}
diff --git a/src/kernel/tests/lib/tst_wallclock.c b/src/kernel/tests/lib/tst_wallclock.c
new file mode 100644
index 0000000..282d6ad
--- /dev/null
+++ b/src/kernel/tests/lib/tst_wallclock.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Linaro Limited. All rights reserved.
+ * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
+ */
+
+#include <errno.h>
+
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+#include "tst_timer.h"
+#include "tst_clocks.h"
+#include "tst_wallclock.h"
+#include "lapi/posix_clocks.h"
+
+static struct timespec real_begin, mono_begin;
+
+static int clock_saved;
+
+void tst_wallclock_save(void)
+{
+ /* save initial monotonic time to restore it when needed */
+
+ if (tst_clock_gettime(CLOCK_REALTIME, &real_begin))
+ tst_brk(TBROK | TERRNO, "tst_clock_gettime() realtime failed");
+
+ if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin)) {
+ if (errno == EINVAL) {
+ tst_brk(TCONF | TERRNO,
+ "tst_clock_gettime() didn't support CLOCK_MONOTONIC_RAW");
+ }
+
+ tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
+ }
+
+ clock_saved = 1;
+}
+
+void tst_wallclock_restore(void)
+{
+ static struct timespec mono_end, elapsed, adjust;
+
+ if (!clock_saved)
+ return;
+
+ clock_saved = 0;
+
+ if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end))
+ tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
+
+ elapsed = tst_timespec_diff(mono_end, mono_begin);
+
+ adjust = tst_timespec_add(real_begin, elapsed);
+
+ /* restore realtime clock based on monotonic delta */
+
+ if (tst_clock_settime(CLOCK_REALTIME, &adjust))
+ tst_brk(TBROK | TERRNO, "tst_clock_settime() realtime failed");
+}
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/CMakeLists.txt b/src/kernel/tests/testcases/kernel/syscalls/ioctl/CMakeLists.txt
new file mode 100644
index 0000000..6f7c5bb
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/CMakeLists.txt
@@ -0,0 +1,45 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(xloop-kernel-test-ioctl_xloop)
+
+# test ioctl_xloop01
+add_executable(ioctl_xloop01 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop01.c)
+target_link_libraries(ioctl_xloop01 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop01 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop02
+add_executable(ioctl_xloop02 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop02.c)
+target_link_libraries(ioctl_xloop02 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop02 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop03
+add_executable(ioctl_xloop03 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop03.c)
+target_link_libraries(ioctl_xloop03 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop03 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop04
+add_executable(ioctl_xloop04 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop04.c)
+target_link_libraries(ioctl_xloop04 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop04 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop05
+add_executable(ioctl_xloop05 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop05.c)
+target_link_libraries(ioctl_xloop05 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop05 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop06
+add_executable(ioctl_xloop06 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop06.c)
+target_link_libraries(ioctl_xloop06 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop06 DESTINATION bin
+ COMPONENT test)
+
+# test ioctl_xloop07
+add_executable(ioctl_xloop07 ${CMAKE_CURRENT_SOURCE_DIR}/ioctl_xloop07.c)
+target_link_libraries(ioctl_xloop07 LINK_PUBLIC libltp)
+install(TARGETS ioctl_xloop07 DESTINATION bin
+ COMPONENT test)
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop01.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop01.c
new file mode 100644
index 0000000..58bb692
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop01.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice.
+ * It is designed to test XLO_FLAGS_AUTOCLEAR and XLO_FLAGS_PARTSCAN flag.
+ *
+ * For XLO_FLAGS_AUTOCLEAR flag, we only check autoclear field value in sys
+ * directory and also get xlo_flags by using XLOOP_GET_STATUS.
+ *
+ * For XLO_FLAGS_PARTSCAN flag, it is the same as XLO_FLAGS_AUTOCLEAR flag.
+ * But we also check whether we can scan partition table correctly ie check
+ * whether /dev/xloopnp1 and /sys/bloclk/xloop0/xloop0p1 existed.
+ *
+ * For XLO_FLAGS_AUTOCLEAR flag, it can be clear. For XLO_FLAGS_PARTSCAN flag,
+ * it cannot be clear. We also check this.
+ *
+ * It is also a regression test for kernel
+ * commit 10c70d95c0f2 ("block: remove the bd_openers checks in blk_drop_partitions")
+ * commit 6ac92fb5cdff ("xloop: Fix wrong masking of status flags").
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+static char dev_path[1024], backing_path[1024], backing_file_path[1024];
+static int dev_num, attach_flag, dev_fd, parted_sup;
+
+/*
+ * In drivers/block/xloop.c code, set status function doesn't handle
+ * XLO_FLAGS_READ_ONLY flag and ingore it. Only xloop_set_fd with read only mode
+ * file_fd, xlo_flags will include XLO_FLAGS_READ_ONLY and it's the same for
+ * XLO_FLAGS_DIRECT_IO.
+ */
+#define SET_FLAGS (XLO_FLAGS_AUTOCLEAR | XLO_FLAGS_PARTSCAN | XLO_FLAGS_READ_ONLY | XLO_FLAGS_DIRECT_IO)
+#define GET_FLAGS (XLO_FLAGS_AUTOCLEAR | XLO_FLAGS_PARTSCAN)
+
+static char partscan_path[1024], autoclear_path[1024];
+static char xloop_partpath[1026], sys_xloop_partpath[1026];
+
+static void check_xloop_value(int set_flag, int get_flag, int autoclear_field)
+{
+ struct xloop_info xloopinfo = {0}, xloopinfoget = {0};
+ int ret;
+
+ xloopinfo.xlo_flags = set_flag;
+ SAFE_IOCTL(dev_fd, XLOOP_SET_STATUS, &xloopinfo);
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS, &xloopinfoget);
+
+ if (xloopinfoget.xlo_flags & ~get_flag)
+ tst_res(TFAIL, "expect %d but got %d", get_flag, xloopinfoget.xlo_flags);
+ else
+ tst_res(TPASS, "get expected xlo_flag %d", xloopinfoget.xlo_flags);
+
+ TST_ASSERT_INT(partscan_path, 1);
+ TST_ASSERT_INT(autoclear_path, autoclear_field);
+
+ if (!parted_sup) {
+ tst_res(TINFO, "Current environment doesn't have parted disk, skip it");
+ return;
+ }
+
+ ret = TST_RETRY_FN_EXP_BACKOFF(access(xloop_partpath, F_OK), TST_RETVAL_EQ0, 30);
+ if (ret == 0)
+ tst_res(TPASS, "access %s succeeds", xloop_partpath);
+ else
+ tst_res(TFAIL, "access %s fails", xloop_partpath);
+
+ ret = TST_RETRY_FN_EXP_BACKOFF(access(sys_xloop_partpath, F_OK), TST_RETVAL_EQ0, 30);
+ if (ret == 0)
+ tst_res(TPASS, "access %s succeeds", sys_xloop_partpath);
+ else
+ tst_res(TFAIL, "access %s fails", sys_xloop_partpath);
+}
+
+static void verify_ioctl_xloop(void)
+{
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+
+ TST_ASSERT_INT(partscan_path, 0);
+ TST_ASSERT_INT(autoclear_path, 0);
+ TST_ASSERT_STR(backing_path, backing_file_path);
+
+ check_xloop_value(SET_FLAGS, GET_FLAGS, 1);
+
+ tst_res(TINFO, "Test flag can be clear");
+ check_xloop_value(0, XLO_FLAGS_PARTSCAN, 0);
+
+ tst_detach_device_by_fd(dev_path, dev_fd);
+ attach_flag = 0;
+}
+
+static void setup(void)
+{
+ int ret;
+ const char *const cmd_parted[] = {"parted", "-s", "test.img", "mklabel", "msdos", "mkpart",
+ "primary", "ext4", "1M", "10M", NULL};
+
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ tst_fill_file("test.img", 0, 1024 * 1024, 10);
+
+ ret = tst_cmd(cmd_parted, NULL, NULL, TST_CMD_PASS_RETVAL);
+ switch (ret) {
+ case 0:
+ parted_sup = 1;
+ break;
+ case 255:
+ tst_res(TCONF, "parted binary not installed or failed");
+ break;
+ default:
+ tst_res(TCONF, "parted exited with %i", ret);
+ break;
+ }
+
+ sprintf(partscan_path, "/sys/block/xloop%d/xloop/partscan", dev_num);
+ sprintf(autoclear_path, "/sys/block/xloop%d/xloop/autoclear", dev_num);
+ sprintf(backing_path, "/sys/block/xloop%d/xloop/backing_file", dev_num);
+ sprintf(sys_xloop_partpath, "/sys/block/xloop%d/xloop%dp1", dev_num, dev_num);
+ sprintf(backing_file_path, "%s/test.img", tst_get_tmpdir());
+ sprintf(xloop_partpath, "%sp1", dev_path);
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = verify_ioctl_xloop,
+ .needs_root = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ },
+ .tags = (const struct tst_tag[]) {
+ {"linux-git", "10c70d95c0f2"},
+ {"linux-git", "6ac92fb5cdff"},
+ {}
+ },
+ .needs_tmpdir = 1,
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop02.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop02.c
new file mode 100644
index 0000000..895f7f2
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop02.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice.
+ *
+ * It is designed to test XLO_FLAGS_READ_ONLY (similar as xlosetup -r)
+ * and XLOOP_CHANGE_FD.
+ *
+ * For XLOOP_CHANGE_FD, this operation is possible only if the xloop device
+ * is read-only and the new backing store is the same size and type as the
+ * old backing store.
+ *
+ * If using XLOOP_CONFIGURE ioctl, we can set XLO_FLAGS_READ_ONLY
+ * flag even though backing file with write mode.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+static int file_fd, file_change_fd, file_fd_invalid;
+static char backing_path[1024], backing_file_path[1024], backing_file_change_path[1024];
+static int attach_flag, dev_fd, xloop_configure_sup = 1;
+static char xloop_ro_path[1024], dev_path[1024];
+static struct xloop_config xloopconfig;
+
+static struct tcase {
+ int mode;
+ int ioctl;
+ char *message;
+} tcases[] = {
+ {O_RDONLY, XLOOP_SET_FD, "Using XLOOP_SET_FD to setup xloopdevice"},
+ {O_RDWR, XLOOP_CONFIGURE, "Using XLOOP_CONFIGURE with read_only flag"},
+};
+
+static void verify_ioctl_xloop(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+ struct xloop_info xloopinfoget;
+
+ if (tc->ioctl == XLOOP_CONFIGURE && !xloop_configure_sup) {
+ tst_res(TCONF, "XLOOP_CONFIGURE ioctl not supported");
+ return;
+ }
+
+ tst_res(TINFO, "%s", tc->message);
+ file_fd = SAFE_OPEN("test.img", tc->mode);
+
+ if (tc->ioctl == XLOOP_SET_FD) {
+ SAFE_IOCTL(dev_fd, XLOOP_SET_FD, file_fd);
+ } else {
+ xloopconfig.fd = file_fd;
+ SAFE_IOCTL(dev_fd, XLOOP_CONFIGURE, &xloopconfig);
+ }
+ attach_flag = 1;
+
+ TST_ASSERT_INT(xloop_ro_path, 1);
+ TST_ASSERT_STR(backing_path, backing_file_path);
+
+ memset(&xloopinfoget, 0, sizeof(xloopinfoget));
+
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS, &xloopinfoget);
+
+ if (xloopinfoget.xlo_flags & ~XLO_FLAGS_READ_ONLY)
+ tst_res(TFAIL, "xlo_flags has unexpected %d flag", xloopinfoget.xlo_flags);
+ else
+ tst_res(TPASS, "xlo_flags only has default XLO_FLAGS_READ_ONLY flag");
+
+ TEST(write(dev_fd, "xx", 2));
+ if (TST_RET != -1)
+ tst_res(TFAIL, "write succeed unexpectedly");
+ else
+ tst_res(TPASS | TTERRNO, "Can not write data in RO mode");
+
+ TEST(ioctl(dev_fd, XLOOP_CHANGE_FD, file_change_fd));
+ if (TST_RET) {
+ tst_res(TFAIL | TTERRNO, "XLOOP_CHANGE_FD failed");
+ } else {
+ tst_res(TPASS, "XLOOP_CHANGE_FD succeeded");
+ TST_ASSERT_INT(xloop_ro_path, 1);
+ TST_ASSERT_STR(backing_path, backing_file_change_path);
+ }
+
+ TEST(ioctl(dev_fd, XLOOP_CHANGE_FD, file_fd_invalid));
+ if (TST_RET) {
+ if (TST_ERR == EINVAL)
+ tst_res(TPASS | TTERRNO, "XLOOP_CHANGE_FD failed as expected");
+ else
+ tst_res(TFAIL | TTERRNO, "XLOOP_CHANGE_FD failed expected EINVAL got");
+ } else {
+ tst_res(TFAIL, "XLOOP_CHANGE_FD succeeded");
+ }
+
+ SAFE_CLOSE(file_fd);
+ tst_detach_device_by_fd(dev_path, dev_fd);
+ attach_flag = 0;
+}
+
+static void setup(void)
+{
+ int dev_num;
+ int ret;
+
+ char *tmpdir = tst_get_tmpdir();
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ tst_fill_file("test.img", 0, 1024, 10);
+ tst_fill_file("test1.img", 0, 1024, 10);
+ tst_fill_file("test2.img", 0, 2048, 20);
+
+ sprintf(backing_path, "/sys/block/xloop%d/xloop/backing_file", dev_num);
+ sprintf(backing_file_path, "%s/test.img", tmpdir);
+ sprintf(backing_file_change_path, "%s/test1.img", tmpdir);
+ sprintf(xloop_ro_path, "/sys/block/xloop%d/ro", dev_num);
+
+ free(tmpdir);
+
+ file_change_fd = SAFE_OPEN("test1.img", O_RDWR);
+ file_fd_invalid = SAFE_OPEN("test2.img", O_RDWR);
+
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+ xloopconfig.fd = -1;
+ ret = ioctl(dev_fd, XLOOP_CONFIGURE, &xloopconfig);
+
+ if (ret && errno != EBADF) {
+ tst_res(TINFO | TERRNO, "XLOOP_CONFIGURE is not supported");
+ xloop_configure_sup = 0;
+ }
+ xloopconfig.info.xlo_flags = XLO_FLAGS_READ_ONLY;
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (file_fd > 0)
+ SAFE_CLOSE(file_fd);
+ if (file_change_fd > 0)
+ SAFE_CLOSE(file_change_fd);
+ if (file_fd_invalid > 0)
+ SAFE_CLOSE(file_fd_invalid);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .tcnt = ARRAY_SIZE(tcases),
+ .test = verify_ioctl_xloop,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop03.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop03.c
new file mode 100644
index 0000000..9447cbc
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop03.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice.
+ *
+ * It is designed to test XLOOP_CHANGE_FD can not succeed (get EINVAL error)
+ * when xloop_dev is not read only.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+static char dev_path[1024];
+static int dev_num, dev_fd, file_fd, attach_flag;
+
+static void verify_ioctl_xloop(void)
+{
+ TEST(ioctl(dev_fd, XLOOP_CHANGE_FD, file_fd));
+ if (TST_RET == 0) {
+ tst_res(TFAIL, "XLOOP_CHANGE_FD succeeded unexpectedly");
+ return;
+ }
+ if (TST_ERR == EINVAL)
+ tst_res(TPASS | TTERRNO, "XLOOP_CHANGE_FD failed as expected");
+ else
+ tst_res(TFAIL | TTERRNO, "XLOOP_CHANGE_FD failed expected EINVAL got");
+}
+
+static void setup(void)
+{
+ struct xloop_info xloopinfoget;
+
+ memset(&xloopinfoget, 0, sizeof(xloopinfoget));
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ tst_fill_file("test.img", 0, 1024, 10);
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+ file_fd = SAFE_OPEN("test.img", O_RDWR);
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS, &xloopinfoget);
+
+ if (xloopinfoget.xlo_flags & XLO_FLAGS_READ_ONLY)
+ tst_brk(TCONF, "Current environment has unexpected XLO_FLAGS_READ_ONLY flag");
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (file_fd > 0)
+ SAFE_CLOSE(file_fd);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = verify_ioctl_xloop,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop04.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop04.c
new file mode 100644
index 0000000..adf5cdf
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop04.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice.
+ *
+ * It is designed to test XLOOP_SET_CAPACITY can update a live
+ * xloop device size when we change the size of the underlying
+ * backing file. Also check sys value.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+#define OLD_SIZE 10240
+#define NEW_SIZE 5120
+
+static char dev_path[1024], sys_xloop_sizepath[1024];
+static char *wrbuf;
+static int dev_num, dev_fd, file_fd, attach_flag;
+
+static void verify_ioctl_xloop(void)
+{
+ struct xloop_info xloopinfoget;
+
+ memset(&xloopinfoget, 0, sizeof(xloopinfoget));
+ tst_fill_file("test.img", 0, 1024, OLD_SIZE/1024);
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+
+ TST_ASSERT_INT(sys_xloop_sizepath, OLD_SIZE/512);
+ file_fd = SAFE_OPEN("test.img", O_RDWR);
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS, &xloopinfoget);
+
+ if (xloopinfoget.xlo_flags & XLO_FLAGS_READ_ONLY)
+ tst_brk(TCONF, "Current environment has unexpected XLO_FLAGS_READ_ONLY flag");
+
+ SAFE_TRUNCATE("test.img", NEW_SIZE);
+ SAFE_IOCTL(dev_fd, XLOOP_SET_CAPACITY);
+
+ SAFE_LSEEK(dev_fd, 0, SEEK_SET);
+
+ /*check that we can't write data beyond 5K into xloop device*/
+ TEST(write(dev_fd, wrbuf, OLD_SIZE));
+ if (TST_RET == NEW_SIZE) {
+ tst_res(TPASS, "XLOOP_SET_CAPACITY set xloop size to %d", NEW_SIZE);
+ } else {
+ tst_res(TFAIL, "XLOOP_SET_CAPACITY didn't set xloop size to %d, its size is %ld",
+ NEW_SIZE, TST_RET);
+ }
+
+ TST_ASSERT_INT(sys_xloop_sizepath, NEW_SIZE/512);
+
+ SAFE_CLOSE(file_fd);
+ tst_detach_device_by_fd(dev_path, dev_fd);
+ unlink("test.img");
+ attach_flag = 0;
+}
+
+static void setup(void)
+{
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ wrbuf = SAFE_MALLOC(OLD_SIZE);
+ memset(wrbuf, 'x', OLD_SIZE);
+ sprintf(sys_xloop_sizepath, "/sys/block/xloop%d/size", dev_num);
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (file_fd > 0)
+ SAFE_CLOSE(file_fd);
+ if (wrbuf)
+ free(wrbuf);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = verify_ioctl_xloop,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop05.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop05.c
new file mode 100644
index 0000000..62ee0c8
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop05.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice.
+ *
+ * It is designed to test XLOOP_SET_DIRECT_IO can update a live
+ * xloop device dio mode. It needs the backing file also supports
+ * dio mode and the xlo_offset is aligned with the logical block size.
+ *
+ * The direct I/O error handling is a bit messy on Linux, some filesystems
+ * return error when it coudln't be enabled, some silently fall back to regular
+ * buffered I/O.
+ *
+ * The XLOOP_SET_DIRECT_IO ioctl() may ignore all checks if it cannot get the
+ * logical block size which is the case if the block device pointer in the
+ * backing file inode is not set. In this case the direct I/O appears to be
+ * enabled but falls back to buffered I/O later on. This is the case at least
+ * for Btrfs. Because of that the test passes both with failure as well as
+ * success with non-zero offset.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+#define DIO_MESSAGE "In dio mode"
+#define NON_DIO_MESSAGE "In non dio mode"
+
+static char dev_path[1024], sys_xloop_diopath[1024], backing_file_path[1024];;
+static int dev_num, dev_fd, block_devfd, attach_flag, logical_block_size;
+
+static void check_dio_value(int flag)
+{
+ struct xloop_info xloopinfoget;
+
+ memset(&xloopinfoget, 0, sizeof(xloopinfoget));
+
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS, &xloopinfoget);
+ tst_res(TINFO, "%s", flag ? DIO_MESSAGE : NON_DIO_MESSAGE);
+
+ if (xloopinfoget.xlo_flags & XLO_FLAGS_DIRECT_IO)
+ tst_res(flag ? TPASS : TFAIL, "xlo_flags has XLO_FLAGS_DIRECT_IO flag");
+ else
+ tst_res(flag ? TFAIL : TPASS, "xlo_flags doesn't have XLO_FLAGS_DIRECT_IO flag");
+
+ TST_ASSERT_INT(sys_xloop_diopath, flag);
+}
+
+static void verify_ioctl_xloop(void)
+{
+ struct xloop_info xloopinfo;
+
+ memset(&xloopinfo, 0, sizeof(xloopinfo));
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_STATUS, &xloopinfo), TST_RETVAL_EQ0);
+
+ tst_res(TINFO, "Without setting xlo_offset or sizelimit");
+ SAFE_IOCTL(dev_fd, XLOOP_SET_DIRECT_IO, 1);
+ check_dio_value(1);
+
+ SAFE_IOCTL(dev_fd, XLOOP_SET_DIRECT_IO, 0);
+ check_dio_value(0);
+
+ tst_res(TINFO, "With offset equal to logical_block_size");
+ xloopinfo.xlo_offset = logical_block_size;
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_STATUS, &xloopinfo), TST_RETVAL_EQ0);
+ TEST(ioctl(dev_fd, XLOOP_SET_DIRECT_IO, 1));
+ if (TST_RET == 0) {
+ tst_res(TPASS, "XLOOP_SET_DIRECT_IO succeeded");
+ check_dio_value(1);
+ SAFE_IOCTL(dev_fd, XLOOP_SET_DIRECT_IO, 0);
+ } else {
+ tst_res(TFAIL | TTERRNO, "XLOOP_SET_DIRECT_IO failed");
+ }
+
+ tst_res(TINFO, "With nonzero offset less than logical_block_size");
+ xloopinfo.xlo_offset = logical_block_size / 2;
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_STATUS, &xloopinfo), TST_RETVAL_EQ0);
+
+ TEST(ioctl(dev_fd, XLOOP_SET_DIRECT_IO, 1));
+ if (TST_RET == 0) {
+ tst_res(TPASS, "XLOOP_SET_DIRECT_IO succeeded, offset is ignored");
+ SAFE_IOCTL(dev_fd, XLOOP_SET_DIRECT_IO, 0);
+ return;
+ }
+ if (TST_ERR == EINVAL)
+ tst_res(TPASS | TTERRNO, "XLOOP_SET_DIRECT_IO failed as expected");
+ else
+ tst_res(TFAIL | TTERRNO, "XLOOP_SET_DIRECT_IO failed expected EINVAL got");
+}
+
+static void setup(void)
+{
+ char bd_path[100];
+
+ if (tst_fs_type(".") == TST_TMPFS_MAGIC)
+ tst_brk(TCONF, "tmpfd doesn't support O_DIRECT flag");
+
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ sprintf(sys_xloop_diopath, "/sys/block/xloop%d/xloop/dio", dev_num);
+ tst_fill_file("test.img", 0, 1024, 1024);
+
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+
+ if (ioctl(dev_fd, XLOOP_SET_DIRECT_IO, 0) && errno == EINVAL)
+ tst_brk(TCONF, "XLOOP_SET_DIRECT_IO is not supported");
+
+ /*
+ * from __xloop_update_dio():
+ * We support direct I/O only if xlo_offset is aligned with the
+ * logical I/O size of backing device, and the logical block
+ * size of xloop is bigger than the backing device's and the xloop
+ * needn't transform transfer.
+ */
+ sprintf(backing_file_path, "%s/test.img", tst_get_tmpdir());
+ tst_find_backing_dev(backing_file_path, bd_path);
+ block_devfd = SAFE_OPEN(bd_path, O_RDWR);
+ SAFE_IOCTL(block_devfd, BLKSSZGET, &logical_block_size);
+ tst_res(TINFO, "backing dev(%s) logical_block_size is %d", bd_path, logical_block_size);
+ SAFE_CLOSE(block_devfd);
+ if (logical_block_size > 512)
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_BLOCK_SIZE, logical_block_size), TST_RETVAL_EQ0);
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (block_devfd > 0)
+ SAFE_CLOSE(block_devfd);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = verify_ioctl_xloop,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop06.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop06.c
new file mode 100644
index 0000000..4bfa63e
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop06.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic error test about the invalid block size of xloopdevice
+ * by using XLOOP_SET_BLOCK_SIZE or XLOOP_CONFIGURE ioctl.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+static char dev_path[1024];
+static int dev_num, dev_fd, file_fd, attach_flag, xloop_configure_sup = 1;
+static unsigned int invalid_value, half_value, unalign_value;
+static struct xloop_config xloopconfig;
+
+static struct tcase {
+ unsigned int *setvalue;
+ int ioctl_flag;
+ char *message;
+} tcases[] = {
+ {&half_value, XLOOP_SET_BLOCK_SIZE,
+ "Using XLOOP_SET_BLOCK_SIZE with arg < 512"},
+
+ {&invalid_value, XLOOP_SET_BLOCK_SIZE,
+ "Using XLOOP_SET_BLOCK_SIZE with arg > PAGE_SIZE"},
+
+ {&unalign_value, XLOOP_SET_BLOCK_SIZE,
+ "Using XLOOP_SET_BLOCK_SIZE with arg != power_of_2"},
+
+ {&half_value, XLOOP_CONFIGURE,
+ "Using XLOOP_CONFIGURE with block_size < 512"},
+
+ {&invalid_value, XLOOP_CONFIGURE,
+ "Using XLOOP_CONFIGURE with block_size > PAGE_SIZE"},
+
+ {&unalign_value, XLOOP_CONFIGURE,
+ "Using XLOOP_CONFIGURE with block_size != power_of_2"},
+};
+
+static void verify_ioctl_xloop(unsigned int n)
+{
+ if (tcases[n].ioctl_flag == XLOOP_CONFIGURE)
+ TEST(ioctl(dev_fd, XLOOP_CONFIGURE, &xloopconfig));
+ else
+ TEST(ioctl(dev_fd, XLOOP_SET_BLOCK_SIZE, *(tcases[n].setvalue)));
+
+ if (TST_RET == 0) {
+ tst_res(TFAIL, "Set block size succeed unexpectedly");
+ if (tcases[n].ioctl_flag == XLOOP_CONFIGURE)
+ tst_detach_device_by_fd(dev_path, dev_fd);
+ return;
+ }
+ if (TST_ERR == EINVAL)
+ tst_res(TPASS | TTERRNO, "Set block size failed as expected");
+ else
+ tst_res(TFAIL | TTERRNO, "Set block size failed expected EINVAL got");
+}
+
+static void run(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+
+ tst_res(TINFO, "%s", tc->message);
+ if (tc->ioctl_flag == XLOOP_SET_BLOCK_SIZE) {
+ if (!attach_flag) {
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+ }
+ verify_ioctl_xloop(n);
+ return;
+ }
+
+ if (tc->ioctl_flag == XLOOP_CONFIGURE && !xloop_configure_sup) {
+ tst_res(TCONF, "XLOOP_CONFIGURE ioctl not supported");
+ return;
+ }
+ if (attach_flag) {
+ tst_detach_device_by_fd(dev_path, dev_fd);
+ attach_flag = 0;
+ }
+ xloopconfig.block_size = *(tc->setvalue);
+ verify_ioctl_xloop(n);
+}
+
+static void setup(void)
+{
+ unsigned int pg_size;
+ int ret;
+
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ tst_fill_file("test.img", 0, 1024, 1024);
+ half_value = 256;
+ pg_size = getpagesize();
+ invalid_value = pg_size * 2 ;
+ unalign_value = pg_size - 1;
+
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+
+ if (ioctl(dev_fd, XLOOP_SET_BLOCK_SIZE, 512) && errno == EINVAL)
+ tst_brk(TCONF, "XLOOP_SET_BLOCK_SIZE is not supported");
+
+ file_fd = SAFE_OPEN("test.img", O_RDWR);
+ xloopconfig.fd = -1;
+ ret = ioctl(dev_fd, XLOOP_CONFIGURE, &xloopconfig);
+ if (ret && errno != EBADF) {
+ tst_res(TINFO | TERRNO, "XLOOP_CONFIGURE is not supported");
+ xloop_configure_sup = 0;
+ return;
+ }
+ xloopconfig.fd = file_fd;
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (file_fd > 0)
+ SAFE_CLOSE(file_fd);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop07.c b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop07.c
new file mode 100644
index 0000000..b51a970
--- /dev/null
+++ b/src/kernel/tests/testcases/kernel/syscalls/ioctl/ioctl_xloop07.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@cn.jujitsu.com>
+ *
+ * This is a basic ioctl test about xloopdevice XLOOP_SET_STATUS64
+ * and XLOOP_GET_STATUS64.
+ * Test its xlo_sizelimit field. If xlo_sizelimit is 0,it means max
+ * available. If sizelimit is less than xloop_size, xloopsize will
+ * be truncated.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "lapi/xloop.h"
+#include "tst_test.h"
+
+static char dev_path[1024], sys_xloop_sizepath[1024], sys_xloop_sizelimitpath[1024];
+static int dev_num, dev_fd, file_fd, attach_flag;
+
+static struct tcase {
+ unsigned int set_sizelimit;
+ unsigned int exp_xloopsize;
+ char *message;
+} tcases[] = {
+ {1024 * 4096, 2048, "When sizelimit is greater than xloopsize "},
+ {1024 * 512, 1024, "When sizelimit is less than xloopsize"},
+};
+
+static void verify_ioctl_xloop(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+ struct xloop_info64 xloopinfo, xloopinfoget;
+
+ tst_res(TINFO, "%s", tc->message);
+ memset(&xloopinfo, 0, sizeof(xloopinfo));
+ memset(&xloopinfoget, 0, sizeof(xloopinfoget));
+
+ xloopinfo.xlo_sizelimit = tc->set_sizelimit;
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_STATUS64, &xloopinfo), TST_RETVAL_EQ0);
+
+ TST_ASSERT_INT(sys_xloop_sizepath, tc->exp_xloopsize);
+ TST_ASSERT_INT(sys_xloop_sizelimitpath, tc->set_sizelimit);
+ SAFE_IOCTL(dev_fd, XLOOP_GET_STATUS64, &xloopinfoget);
+ if (xloopinfoget.xlo_sizelimit == tc->set_sizelimit)
+ tst_res(TPASS, "XLOOP_GET_STATUS64 gets correct xlo_sizelimit(%d)", tc->set_sizelimit);
+ else
+ tst_res(TFAIL, "XLOOP_GET_STATUS64 gets wrong xlo_sizelimit(%llu), expect %d",
+ xloopinfoget.xlo_sizelimit, tc->set_sizelimit);
+ /*Reset*/
+ xloopinfo.xlo_sizelimit = 0;
+ TST_RETRY_FUNC(ioctl(dev_fd, XLOOP_SET_STATUS, &xloopinfo), TST_RETVAL_EQ0);
+}
+
+static void setup(void)
+{
+ dev_num = tst_find_free_xloopdev(dev_path, sizeof(dev_path));
+ if (dev_num < 0)
+ tst_brk(TBROK, "Failed to find free xloop device");
+
+ tst_fill_file("test.img", 0, 1024 * 1024, 1);
+ tst_attach_device(dev_path, "test.img");
+ attach_flag = 1;
+
+ sprintf(sys_xloop_sizepath, "/sys/block/xloop%d/size", dev_num);
+ sprintf(sys_xloop_sizelimitpath, "/sys/block/xloop%d/xloop/sizelimit", dev_num);
+
+ dev_fd = SAFE_OPEN(dev_path, O_RDWR);
+ tst_res(TINFO, "original xloop size 2048 sectors");
+}
+
+static void cleanup(void)
+{
+ if (dev_fd > 0)
+ SAFE_CLOSE(dev_fd);
+ if (file_fd > 0)
+ SAFE_CLOSE(file_fd);
+ if (attach_flag)
+ tst_detach_device(dev_path);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test = verify_ioctl_xloop,
+ .tcnt = ARRAY_SIZE(tcases),
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .needs_drivers = (const char *const []) {
+ "xloop",
+ "xloop_file_fmt_raw",
+ NULL
+ }
+};
diff --git a/src/kernel/uapi_xloop.h b/src/kernel/uapi_xloop.h
new file mode 100644
index 0000000..1bf13c6
--- /dev/null
+++ b/src/kernel/uapi_xloop.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */
+/*
+ * include/linux/xloop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
+ * permitted under the GNU General Public License.
+ */
+#ifndef _UAPI_LINUX_XLOOP_H
+#define _UAPI_LINUX_XLOOP_H
+
+
+#define XLO_NAME_SIZE 64
+#define XLO_KEY_SIZE 32
+
+
+/*
+ * xloop flags
+ */
+enum {
+ XLO_FLAGS_READ_ONLY = 1,
+ XLO_FLAGS_AUTOCLEAR = 4,
+ XLO_FLAGS_PARTSCAN = 8,
+ XLO_FLAGS_DIRECT_IO = 16,
+};
+
+/* XLO_FLAGS that can be set using XLOOP_SET_STATUS(64) */
+#define XLOOP_SET_STATUS_SETTABLE_FLAGS (XLO_FLAGS_AUTOCLEAR | XLO_FLAGS_PARTSCAN)
+
+/* XLO_FLAGS that can be cleared using XLOOP_SET_STATUS(64) */
+#define XLOOP_SET_STATUS_CLEARABLE_FLAGS (XLO_FLAGS_AUTOCLEAR)
+
+/* XLO_FLAGS that can be set using XLOOP_CONFIGURE */
+#define XLOOP_CONFIGURE_SETTABLE_FLAGS (XLO_FLAGS_READ_ONLY | XLO_FLAGS_AUTOCLEAR \
+ | XLO_FLAGS_PARTSCAN | XLO_FLAGS_DIRECT_IO)
+
+#include <asm/posix_types.h> /* for __kernel_old_dev_t */
+#include <linux/types.h> /* for __u64 */
+
+/* Backwards compatibility version */
+struct xloop_info {
+ int xlo_number; /* ioctl r/o */
+ __kernel_old_dev_t xlo_device; /* ioctl r/o */
+ unsigned long xlo_inode; /* ioctl r/o */
+ __kernel_old_dev_t xlo_rdevice; /* ioctl r/o */
+ int xlo_offset;
+ int xlo_encrypt_type;
+ int xlo_encrypt_key_size; /* ioctl w/o */
+ int xlo_flags;
+ char xlo_name[XLO_NAME_SIZE];
+ unsigned char xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */
+ unsigned long xlo_init[2];
+ char reserved[4];
+ int xlo_file_fmt_type;
+};
+
+struct xloop_info64 {
+ __u64 xlo_device; /* ioctl r/o */
+ __u64 xlo_inode; /* ioctl r/o */
+ __u64 xlo_rdevice; /* ioctl r/o */
+ __u64 xlo_offset;
+ __u64 xlo_sizelimit; /* bytes, 0 == max available */
+ __u32 xlo_number; /* ioctl r/o */
+ __u32 xlo_encrypt_type;
+ __u32 xlo_encrypt_key_size; /* ioctl w/o */
+ __u32 xlo_flags;
+ __u8 xlo_file_name[XLO_NAME_SIZE];
+ __u8 xlo_crypt_name[XLO_NAME_SIZE];
+ __u8 xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */
+ __u64 xlo_init[2];
+ __u32 xlo_file_fmt_type;
+};
+
+/**
+ * struct xloop_config - Complete configuration for a xloop device.
+ * @fd: fd of the file to be used as a backing file for the xloop device.
+ * @block_size: block size to use; ignored if 0.
+ * @info: struct xloop_info64 to configure the xloop device with.
+ *
+ * This structure is used with the XLOOP_CONFIGURE ioctl, and can be used to
+ * atomically setup and configure all xloop device parameters at once.
+ */
+struct xloop_config {
+ __u32 fd;
+ __u32 block_size;
+ struct xloop_info64 info;
+ __u64 __reserved[8];
+};
+
+/*
+ * xloop filter types
+ */
+#define XLO_CRYPT_NONE 0
+#define XLO_CRYPT_XOR 1
+#define XLO_CRYPT_DES 2
+#define XLO_CRYPT_FISH2 3 /* Twofish encryption */
+#define XLO_CRYPT_BLOW 4
+#define XLO_CRYPT_CAST128 5
+#define XLO_CRYPT_IDEA 6
+#define XLO_CRYPT_DUMMY 9
+#define XLO_CRYPT_SKIPJACK 10
+#define XLO_CRYPT_CRYPTOAPI 18
+#define MAX_XLO_CRYPT 20
+
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+#define XLOOP_SET_FD 0x4C00
+#define XLOOP_CLR_FD 0x4C01
+#define XLOOP_SET_STATUS 0x4C02
+#define XLOOP_GET_STATUS 0x4C03
+#define XLOOP_SET_STATUS64 0x4C04
+#define XLOOP_GET_STATUS64 0x4C05
+#define XLOOP_CHANGE_FD 0x4C06
+#define XLOOP_SET_CAPACITY 0x4C07
+#define XLOOP_SET_DIRECT_IO 0x4C08
+#define XLOOP_SET_BLOCK_SIZE 0x4C09
+#define XLOOP_CONFIGURE 0x4C0A
+
+/* /dev/xloop-control interface */
+#define XLOOP_CTL_ADD 0x4C80
+#define XLOOP_CTL_REMOVE 0x4C81
+#define XLOOP_CTL_GET_FREE 0x4C82
+#endif /* _UAPI_LINUX_XLOOP_H */
diff --git a/src/kernel/udev/50-xloop.rules b/src/kernel/udev/50-xloop.rules
new file mode 100644
index 0000000..fac04e0
--- /dev/null
+++ b/src/kernel/udev/50-xloop.rules
@@ -0,0 +1,56 @@
+# Adapted from /usr/lib/udev/rules.d/60-persistent-storage.rules
+# Only handle /dev/xloop* devices.
+#
+# persistent storage links: /dev/disk/{by-id,by-uuid,by-label,by-path}
+# scheme based on "Linux persistent device names", 2004, Hannes Reinecke <hare@suse.de>
+
+ACTION=="remove", GOTO="xloop_storage_end"
+ENV{UDEV_DISABLE_PERSISTENT_STORAGE_RULES_FLAG}=="1", GOTO="xloop_storage_end"
+
+SUBSYSTEM!="block", GOTO="xloop_storage_end"
+KERNEL!="xloop*", GOTO="xloop_storage_end"
+
+# ignore partitions that span the entire disk
+TEST=="whole_disk", GOTO="xloop_storage_end"
+
+# For partitions import parent disk ID_* information, except ID_FS_*.
+#
+# This is particularly important on media where a filesystem superblock and
+# partition table are found on the same level, e.g. common Linux distro ISO
+# installation media.
+#
+# In the case where a partition device points to the same filesystem that
+# was detected on the parent disk, the ID_FS_* information is already
+# present on the partition devices as well as the parent, so no need to
+# propagate it. In the case where the partition device points to a different
+# filesystem, merging the parent ID_FS_ properties would lead to
+# inconsistencies, so we avoid doing so.
+ENV{DEVTYPE}=="partition", \
+ IMPORT{parent}="ID_[!F]*", IMPORT{parent}="ID_", \
+ IMPORT{parent}="ID_F[!S]*", IMPORT{parent}="ID_F", \
+ IMPORT{parent}="ID_FS[!_]*", IMPORT{parent}="ID_FS"
+
+# by-path
+ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id"
+KERNEL!="mmcblk[0-9]boot[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
+ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
+# compatible links for ATA devices
+KERNEL!="mmcblk[0-9]boot[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_PATH_ATA_COMPAT}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH_ATA_COMPAT}"
+ENV{DEVTYPE}=="partition", ENV{ID_PATH_ATA_COMPAT}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH_ATA_COMPAT}-part%n"
+
+# probe filesystem metadata of disks
+KERNEL!="sr*", IMPORT{builtin}="blkid"
+
+# by-label/by-uuid links (filesystem metadata)
+ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
+ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
+
+# by-id (World Wide Name)
+ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}"
+ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}-part%n"
+
+# by-partlabel/by-partuuid links (partition metadata)
+ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
+ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
+
+LABEL="xloop_storage_end"
diff --git a/src/kernel/xloop_file_fmt.c b/src/kernel/xloop_file_fmt.c
new file mode 100644
index 0000000..6c4902f
--- /dev/null
+++ b/src/kernel/xloop_file_fmt.c
@@ -0,0 +1,356 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt.c
+ *
+ * File format subsystem for the xloop device module.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "xloop_file_fmt.h"
+#include "xloop_main.h"
+
+/* storage for all registered file format drivers */
+static struct xloop_file_fmt_driver *xloop_file_fmt_drivers[MAX_XLO_FILE_FMT] = {
+ NULL
+};
+
+int xloop_file_fmt_register_driver(struct xloop_file_fmt_driver *drv)
+{
+ int ret = 0;
+
+ if (drv == NULL)
+ return -EFAULT;
+
+ if (drv->file_fmt_type > MAX_XLO_FILE_FMT)
+ return -EINVAL;
+
+ if (xloop_file_fmt_drivers[drv->file_fmt_type] == NULL) {
+ xloop_file_fmt_drivers[drv->file_fmt_type] = drv;
+ pr_info("successfully registered file format driver %s\n", drv->name);
+ } else {
+ pr_warn("driver for file format already registered\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(xloop_file_fmt_register_driver);
+
+void xloop_file_fmt_unregister_driver(struct xloop_file_fmt_driver *drv)
+{
+ if (drv == NULL)
+ return;
+
+ if (drv->file_fmt_type > MAX_XLO_FILE_FMT)
+ return;
+
+ xloop_file_fmt_drivers[drv->file_fmt_type] = NULL;
+ pr_info("successfully unregistered file format driver %s\n", drv->name);
+}
+EXPORT_SYMBOL(xloop_file_fmt_unregister_driver);
+
+struct xloop_file_fmt *xloop_file_fmt_alloc(void)
+{
+ return kzalloc(sizeof(struct xloop_file_fmt), GFP_KERNEL);
+}
+
+void xloop_file_fmt_free(struct xloop_file_fmt *xlo_fmt)
+{
+ kfree(xlo_fmt);
+}
+
+int xloop_file_fmt_set_xlo(struct xloop_file_fmt *xlo_fmt, struct xloop_device *xlo)
+{
+ if (xlo_fmt == NULL)
+ return -EINVAL;
+
+ xlo_fmt->xlo = xlo;
+
+ return 0;
+}
+EXPORT_SYMBOL(xloop_file_fmt_set_xlo);
+
+struct xloop_device *xloop_file_fmt_get_xlo(struct xloop_file_fmt *xlo_fmt)
+{
+ return xlo_fmt->xlo;
+}
+EXPORT_SYMBOL(xloop_file_fmt_get_xlo);
+
+struct device *xloop_file_fmt_to_dev(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ return xloop_device_to_dev(xlo);
+}
+EXPORT_SYMBOL(xloop_file_fmt_to_dev);
+
+int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt,
+ u32 file_fmt_type)
+{
+ struct xloop_file_fmt_ops *ops;
+ struct module *drv;
+ int ret = 0;
+
+ if (file_fmt_type > MAX_XLO_FILE_FMT)
+ return -EINVAL;
+
+ xlo_fmt->file_fmt_type = file_fmt_type;
+
+ if (xlo_fmt->file_fmt_state != file_fmt_uninitialized) {
+ dev_warn(xloop_file_fmt_to_dev(xlo_fmt), "file format is "
+ "initialized already\n");
+ return -EINVAL;
+ }
+
+ /* check if new file format driver is registered */
+ if (xloop_file_fmt_drivers[xlo_fmt->file_fmt_type] == NULL) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver is "
+ "not available\n");
+ return -ENODEV;
+ }
+
+ dev_info(xloop_file_fmt_to_dev(xlo_fmt), "use file format driver %s\n",
+ xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->name);
+
+ drv = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->owner;
+ if (!try_module_get(drv)) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "file format driver %s can "
+ "not be accessed\n",
+ xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->name);
+ return -ENODEV;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->init)) {
+ ret = ops->init(xlo_fmt);
+ if (ret < 0)
+ goto free_drv;
+ }
+
+ /* after increasing the refcount of file format driver module and
+ * the successful initialization, the file format is initialized */
+ xlo_fmt->file_fmt_state = file_fmt_initialized;
+
+ return ret;
+
+free_drv:
+ module_put(drv);
+ xlo_fmt->file_fmt_state = file_fmt_uninitialized;
+ return ret;
+}
+
+void xloop_file_fmt_exit(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_ops *ops;
+ struct module *drv;
+
+ if (xlo_fmt->file_fmt_state != file_fmt_initialized) {
+ dev_warn(xloop_file_fmt_to_dev(xlo_fmt), "file format is "
+ "uninitialized already\n");
+ return;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->exit))
+ ops->exit(xlo_fmt);
+
+ drv = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->owner;
+ module_put(drv);
+
+ /* after decreasing the refcount of file format driver module,
+ * the file format is uninitialized */
+ xlo_fmt->file_fmt_state = file_fmt_uninitialized;
+}
+
+int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not read\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->read))
+ return ops->read(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not read aio\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->read_aio))
+ return ops->read_aio(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not write\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->write))
+ return ops->write(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not write aio\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->write_aio))
+ return ops->write_aio(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not write zeros\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->write_zeros))
+ return ops->write_zeros(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not discard\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->discard))
+ return ops->discard(xlo_fmt, rq);
+ else
+ return -EIO;
+}
+
+int xloop_file_fmt_flush(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not flush\n");
+ return -EINVAL;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->flush))
+ return ops->flush(xlo_fmt);
+
+ return 0;
+}
+
+loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt,
+ struct file *file, loff_t offset, loff_t sizelimit)
+{
+ struct xloop_file_fmt_ops *ops;
+
+ if (unlikely(xlo_fmt->file_fmt_state != file_fmt_initialized)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "file format "
+ "is not initialized, can not read sector size\n");
+ return 0;
+ }
+
+ ops = xloop_file_fmt_drivers[xlo_fmt->file_fmt_type]->ops;
+ if (likely(ops->sector_size))
+ return ops->sector_size(xlo_fmt, file, offset, sizelimit);
+ else
+ return 0;
+}
+
+int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt,
+ u32 file_fmt_type_new)
+{
+ if (file_fmt_type_new > MAX_XLO_FILE_FMT)
+ return -EINVAL;
+
+ dev_info(xloop_file_fmt_to_dev(xlo_fmt), "change file format\n");
+
+ /* Unload the old file format driver if the file format is
+ * initialized */
+ if (xlo_fmt->file_fmt_state == file_fmt_initialized)
+ xloop_file_fmt_exit(xlo_fmt);
+
+ /* Load the new file format driver because the file format is
+ * uninitialized now */
+ return xloop_file_fmt_init(xlo_fmt, file_fmt_type_new);
+}
+
+ssize_t xloop_file_fmt_print_type(u32 file_fmt_type, char *file_fmt_name)
+{
+ ssize_t len = 0;
+
+ switch (file_fmt_type) {
+ case XLO_FILE_FMT_RAW:
+ len = sprintf(file_fmt_name, "%s", "RAW");
+ break;
+ case XLO_FILE_FMT_QCOW:
+ len = sprintf(file_fmt_name, "%s", "QCOW");
+ break;
+ case XLO_FILE_FMT_VDI:
+ len = sprintf(file_fmt_name, "%s", "VDI");
+ break;
+ case XLO_FILE_FMT_VMDK:
+ len = sprintf(file_fmt_name, "%s", "VMDK");
+ break;
+ default:
+ len = sprintf(file_fmt_name, "%s", "ERROR: Unsupported xloop "
+ "file format!");
+ break;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL(xloop_file_fmt_print_type);
diff --git a/src/kernel/xloop_file_fmt.h b/src/kernel/xloop_file_fmt.h
new file mode 100644
index 0000000..20589c1
--- /dev/null
+++ b/src/kernel/xloop_file_fmt.h
@@ -0,0 +1,388 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt.h
+ *
+ * File format subsystem for the xloop device module.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#ifndef _LINUX_XLOOP_FILE_FMT_H
+#define _LINUX_XLOOP_FILE_FMT_H
+
+#include "xloop_main.h"
+
+struct xloop_file_fmt;
+
+#define XLO_FILE_FMT_RAW 0
+#define XLO_FILE_FMT_QCOW 1
+#define XLO_FILE_FMT_VDI 2
+#define XLO_FILE_FMT_VMDK 3
+#define MAX_XLO_FILE_FMT (XLO_FILE_FMT_VMDK + 1)
+
+/**
+ * struct xloop_file_fmt_ops - File format subsystem operations
+ *
+ * Data structure representing the file format subsystem interface.
+ */
+struct xloop_file_fmt_ops {
+ /**
+ * @init: Initialization callback function
+ */
+ int (*init) (struct xloop_file_fmt *xlo_fmt);
+
+ /**
+ * @exit: Release callback function
+ */
+ void (*exit) (struct xloop_file_fmt *xlo_fmt);
+
+ /**
+ * @read: Read IO callback function
+ */
+ int (*read) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @write: Write IO callback function
+ */
+ int (*write) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @read_aio: Asynchronous read IO callback function
+ */
+ int (*read_aio) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @write_aio: Asynchronous write IO callback function
+ */
+ int (*write_aio) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @zero: Zero (discard) IO callback function
+ */
+ int (*write_zeros) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @discard: Discard IO callback function
+ */
+ int (*discard) (struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+ /**
+ * @flush: Flush callback function
+ */
+ int (*flush) (struct xloop_file_fmt *xlo_fmt);
+
+ /**
+ * @sector_size: Get sector size callback function
+ */
+ loff_t (*sector_size) (struct xloop_file_fmt *xlo_fmt,
+ struct file *file, loff_t offset, loff_t sizelimit);
+};
+
+/**
+ * struct xloop_file_fmt_driver - File format subsystem driver
+ *
+ * Data structure to implement file format drivers for the file format
+ * subsystem.
+ */
+struct xloop_file_fmt_driver {
+ /**
+ * @name: Name of the file format driver
+ */
+ const char *name;
+
+ /**
+ * @file_fmt_type: xloop file format type of the file format driver
+ */
+ const u32 file_fmt_type;
+
+ /**
+ * @ops: Driver's implemented file format operations
+ */
+ struct xloop_file_fmt_ops *ops;
+
+ /**
+ * @ops: Owner of the file format driver
+ */
+ struct module *owner;
+};
+
+/*
+ * states of the file format
+ *
+ * transitions:
+ * xloop_file_fmt_init(...)
+ * ---> uninitialized ------------------------------> initialized
+ * xloop_file_fmt_exit(...)
+ * initialized ------------------------------> uninitialized
+ * xloop_file_fmt_read(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_read_aio(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_write(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_write_aio(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_discard(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_flush(...)
+ * initialized ------------------------------> initialized
+ * xloop_file_fmt_sector_size(...)
+ * initialized ------------------------------> initialized
+ *
+ * xloop_file_fmt_change(...)
+ * +-----------------------------------------------------------+
+ * | exit(...) init(...) |
+ * | initialized -------> uninitialized -------> initialized |
+ * +-----------------------------------------------------------+
+ */
+enum {
+ file_fmt_uninitialized = 0,
+ file_fmt_initialized
+};
+
+/**
+ * struct xloop_file_fmt - xloop file format
+ *
+ * Data structure to use with the file format the xloop file format subsystem.
+ */
+struct xloop_file_fmt {
+ /**
+ * @file_fmt_type: Current type of the xloop file format
+ */
+ u32 file_fmt_type;
+
+ /**
+ * @file_fmt_state: Current state of the xloop file format
+ */
+ int file_fmt_state;
+
+ /**
+ * @xlo: Link to a file format's xloop device
+ */
+ struct xloop_device *xlo;
+
+ /**
+ * @private_data: Optional link to a file format's driver specific data
+ */
+ void *private_data;
+};
+
+
+/* subsystem functions for the driver implementation */
+
+/**
+ * xloop_file_fmt_register_driver - Register a xloop file format driver
+ * @drv: File format driver
+ *
+ * Registers the specified xloop file format driver @drv by the xloop file format
+ * subsystem.
+ */
+extern int xloop_file_fmt_register_driver(struct xloop_file_fmt_driver *drv);
+
+/**
+ * xloop_file_fmt_unregister_driver - Unregister a xloop file format driver
+ * @drv: File format driver
+ *
+ * Unregisters the specified xloop file format driver @drv from the xloop file
+ * format subsystem.
+ */
+extern void xloop_file_fmt_unregister_driver(struct xloop_file_fmt_driver *drv);
+
+
+/* subsystem functions for subsystem usage */
+
+/**
+ * xloop_file_fmt_alloc - Allocate a xloop file format
+ *
+ * Dynamically allocates a xloop file format and returns a pointer to the
+ * created xloop file format.
+ */
+extern struct xloop_file_fmt *xloop_file_fmt_alloc(void);
+
+/**
+ * xloop_file_fmt_free - Free an allocated xloop file format
+ * @xlo_fmt: xloop file format
+ *
+ * Frees the already allocated xloop file format @xlo_fmt.
+ */
+extern void xloop_file_fmt_free(struct xloop_file_fmt *xlo_fmt);
+
+/**
+ * xloop_file_fmt_set_xlo - Set the xloop file format's xloop device
+ * @xlo_fmt: xloop file format
+ * @xlo: xloop device
+ *
+ * The link to the xloop device @xlo is set in the xloop file format @xlo_fmt.
+ */
+extern int xloop_file_fmt_set_xlo(struct xloop_file_fmt *xlo_fmt,
+ struct xloop_device *xlo);
+
+/**
+ * xloop_file_fmt_get_xlo - Get the xloop file format's xloop device
+ * @xlo_fmt: xloop file format
+ *
+ * Returns a pointer to the xloop device of the xloop file format @xlo_fmt.
+ */
+extern struct xloop_device *xloop_file_fmt_get_xlo(struct xloop_file_fmt *xlo_fmt);
+
+/**
+ * xloop_file_fmt_to_dev - Get the xloop file format's disk device
+ * @xlo_fmt: xloop file format
+ *
+ * Returns a pointer to the disk device of the xloop file format's xloop device.
+ */
+extern inline struct device *xloop_file_fmt_to_dev(struct xloop_file_fmt *xlo_fmt);
+
+/**
+ * xloop_file_fmt_init - Initialize a xloop file format
+ * @xlo_fmt: xloop file format
+ * @file_fmt_type: Type of the file format
+ *
+ * Initializes the specified xloop file format @xlo_fmt and sets up the correct
+ * file format type @file_fmt_type. Depending on @file_fmt_type, the correct
+ * xloop file format driver is loaded in the subsystems backend. If no xloop file
+ * format driver for the specified file format is available an error is
+ * returned.
+ */
+extern int xloop_file_fmt_init(struct xloop_file_fmt *xlo_fmt,
+ u32 file_fmt_type);
+
+/**
+ * xloop_file_fmt_exit - Release a xloop file format
+ * @xlo_fmt: xloop file format
+ *
+ * Releases the specified xloop file format @xlo_fmt and all its resources.
+ */
+extern void xloop_file_fmt_exit(struct xloop_file_fmt *xlo_fmt);
+
+/**
+ * xloop_file_fmt_read - Read IO from a xloop file format
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Reads IO from the file format's xloop device by sending the IO read request
+ * @rq to the xloop file format subsystem. The subsystem calls the registered
+ * callback function of the suitable xloop file format driver.
+ */
+extern int xloop_file_fmt_read(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_read_aio - Read IO from a xloop file format asynchronously
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Reads IO from the file format's xloop device asynchronously by sending the
+ * IO read aio request @rq to the xloop file format subsystem. The subsystem
+ * calls the registered callback function of the suitable xloop file format
+ * driver.
+ */
+extern int xloop_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_write - Write IO to a xloop file format
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Write IO to the file format's xloop device by sending the IO write request
+ * @rq to the xloop file format subsystem. The subsystem calls the registered
+ * callback function of the suitable xloop file format driver.
+ */
+extern int xloop_file_fmt_write(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_write_aio - Write IO to a xloop file format asynchronously
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Write IO to the file format's xloop device asynchronously by sending the
+ * IO write aio request @rq to the xloop file format subsystem. The subsystem
+ * calls the registered callback function of the suitable xloop file format
+ * driver.
+ */
+extern int xloop_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_write_zeros - Zero (discard) IO on a xloop file format
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Zero (discard) IO on the file format's xloop device by sending the IO write
+ * zeros request @rq to the xloop file format subsystem. The subsystem calls the
+ * registered callback function of the suitable xloop file format driver.
+ */
+extern int xloop_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_discard - Discard IO on a xloop file format
+ * @xlo_fmt: xloop file format
+ * @rq: IO Request
+ *
+ * Discard IO on the file format's xloop device by sending the IO discard
+ * request @rq to the xloop file format subsystem. The subsystem calls the
+ * registered callback function of the suitable xloop file format driver.
+ */
+extern int xloop_file_fmt_discard(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq);
+
+/**
+ * xloop_file_fmt_flush - Flush a xloop file format
+ * @xlo_fmt: xloop file format
+ *
+ * Flush the file format's xloop device by calling the registered callback
+ * function of the suitable xloop file format driver.
+ */
+extern int xloop_file_fmt_flush(struct xloop_file_fmt *xlo_fmt);
+
+/**
+ * xloop_file_fmt_sector_size - Get sector size of a xloop file format
+ * @xlo_fmt: xloop file format
+ * @file: xloop file formats file for sector size calculation
+ * @offset: Offset within the file for sector size calculation
+ * @sizelimit: Sizelimit of the file for sector size calculation
+ *
+ * Returns the physical sector size of the given xloop file format's file.
+ * If the xloop file format implements a sparse disk image format, then this
+ * function returns the virtual sector size.
+ */
+extern loff_t xloop_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt,
+ struct file *file, loff_t offset, loff_t sizelimit);
+
+/**
+ * xloop_file_fmt_change - Change the xloop file format's type
+ * @xlo_fmt: xloop file format
+ * @file_fmt_type_new: xloop file format type
+ *
+ * Changes the file format type of the already initialized xloop file format
+ * @xlo_fmt. Therefore, the function releases the old file format and frees all
+ * of its resources before the xloop file format @xlo_fmt is initialized and set
+ * up with the new file format @file_fmt_type_new.
+ */
+extern int xloop_file_fmt_change(struct xloop_file_fmt *xlo_fmt,
+ u32 file_fmt_type_new);
+
+
+/* helper functions of the subsystem */
+
+/**
+ * xloop_file_fmt_print_type - Convert file format type to string
+ * @file_fmt_type: xloop file format type
+ * @file_fmt_name: xloop file format type string
+ *
+ * Converts the specified numeric @file_fmt_type value into a human readable
+ * string stating the file format as string in @file_fmt_name.
+ */
+extern ssize_t xloop_file_fmt_print_type(u32 file_fmt_type,
+ char *file_fmt_name);
+
+#endif
diff --git a/src/kernel/xloop_file_fmt_qcow_cache.c b/src/kernel/xloop_file_fmt_qcow_cache.c
new file mode 100644
index 0000000..236add5
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_cache.c
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow_cache.c
+ *
+ * QCOW file format driver for the xloop device module.
+ *
+ * Ported QCOW2 implementation of the QEMU project (GPL-2.0):
+ * L2/refcount table cache for the QCOW2 format.
+ *
+ * The copyright (C) 2010 of the original code is owned by
+ * Kevin Wolf <kwolf@redhat.com>
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/types.h>
+#include <linux/limits.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+
+#include "xloop_file_fmt_qcow_main.h"
+#include "xloop_file_fmt_qcow_cache.h"
+
+static inline void *__xloop_file_fmt_qcow_cache_get_table_addr(
+ struct xloop_file_fmt_qcow_cache *c, int table)
+{
+ return (u8 *) c->table_array + (size_t) table * c->table_size;
+}
+
+static inline int __xloop_file_fmt_qcow_cache_get_table_idx(
+ struct xloop_file_fmt_qcow_cache *c, void *table)
+{
+ ptrdiff_t table_offset = (u8 *) table - (u8 *) c->table_array;
+ int idx = table_offset / c->table_size;
+ ASSERT(idx >= 0 && idx < c->size && table_offset % c->table_size == 0);
+ return idx;
+}
+
+static inline const char *__xloop_file_fmt_qcow_cache_get_name(
+ struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ if (c == qcow_data->refcount_block_cache) {
+ return "refcount block";
+ } else if (c == qcow_data->l2_table_cache) {
+ return "L2 table";
+ } else {
+ /* do not abort, because this is not critical */
+ return "unknown";
+ }
+}
+
+struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create(
+ struct xloop_file_fmt *xlo_fmt, int num_tables, unsigned table_size)
+{
+#ifdef CONFIG_DEBUG_DRIVER
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+#endif
+ struct xloop_file_fmt_qcow_cache *c;
+
+ ASSERT(num_tables > 0);
+ ASSERT(is_power_of_2(table_size));
+ ASSERT(table_size >= (1 << QCOW_MIN_CLUSTER_BITS));
+ ASSERT(table_size <= qcow_data->cluster_size);
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ return NULL;
+ }
+
+ c->size = num_tables;
+ c->table_size = table_size;
+ c->entries = vzalloc(sizeof(struct xloop_file_fmt_qcow_cache_table) *
+ num_tables);
+ c->table_array = vzalloc(num_tables * c->table_size);
+
+ if (!c->entries || !c->table_array) {
+ vfree(c->table_array);
+ vfree(c->entries);
+ kfree(c);
+ c = NULL;
+ }
+
+ return c;
+}
+
+void xloop_file_fmt_qcow_cache_destroy(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_file_fmt_qcow_cache *c = qcow_data->l2_table_cache;
+ int i;
+
+ for (i = 0; i < c->size; i++) {
+ ASSERT(c->entries[i].ref == 0);
+ }
+
+ vfree(c->table_array);
+ vfree(c->entries);
+ kfree(c);
+}
+
+static int __xloop_file_fmt_qcow_cache_entry_flush(
+ struct xloop_file_fmt *xlo_fmt, struct xloop_file_fmt_qcow_cache *c, int i)
+{
+ if (!c->entries[i].dirty || !c->entries[i].offset) {
+ return 0;
+ } else {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "flush dirty "
+ "cache tables is not supported yet\n");
+ return -ENOSYS;
+ }
+}
+
+static int __xloop_file_fmt_qcow_cache_do_get(struct xloop_file_fmt *xlo_fmt,
+ struct xloop_file_fmt_qcow_cache *c, u64 offset, void **table,
+ bool read_from_disk)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ int i;
+ int ret;
+ int lookup_index;
+ u64 min_lru_counter = U64_MAX;
+ int min_lru_index = -1;
+ u64 read_offset;
+ size_t len;
+
+ ASSERT(offset != 0);
+
+ if (!IS_ALIGNED(offset, c->table_size)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "cannot get entry "
+ "from %s cache: offset %llx is unaligned\n",
+ __xloop_file_fmt_qcow_cache_get_name(xlo_fmt, c), offset);
+ return -EIO;
+ }
+
+ /* Check if the table is already cached */
+ i = lookup_index = (offset / c->table_size * 4) % c->size;
+ do {
+ const struct xloop_file_fmt_qcow_cache_table *t =
+ &c->entries[i];
+ if (t->offset == offset) {
+ goto found;
+ }
+ if (t->ref == 0 && t->lru_counter < min_lru_counter) {
+ min_lru_counter = t->lru_counter;
+ min_lru_index = i;
+ }
+ if (++i == c->size) {
+ i = 0;
+ }
+ } while (i != lookup_index);
+
+ if (min_lru_index == -1) {
+ BUG();
+ panic("Oops: This can't happen in current synchronous code, "
+ "but leave the check here as a reminder for whoever "
+ "starts using AIO with the QCOW cache");
+ }
+
+ /* Cache miss: write a table back and replace it */
+ i = min_lru_index;
+
+ ret = __xloop_file_fmt_qcow_cache_entry_flush(xlo_fmt, c, i);
+ if (ret < 0) {
+ return ret;
+ }
+
+ c->entries[i].offset = 0;
+ if (read_from_disk) {
+ read_offset = offset;
+ len = kernel_read(xlo->xlo_backing_file,
+ __xloop_file_fmt_qcow_cache_get_table_addr(c, i),
+ c->table_size, &read_offset);
+ if (len < 0) {
+ len = ret;
+ return ret;
+ }
+ }
+
+ c->entries[i].offset = offset;
+
+ /* And return the right table */
+found:
+ c->entries[i].ref++;
+ *table = __xloop_file_fmt_qcow_cache_get_table_addr(c, i);
+
+ return 0;
+}
+
+int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt, u64 offset,
+ void **table)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_file_fmt_qcow_cache *c = qcow_data->l2_table_cache;
+
+ return __xloop_file_fmt_qcow_cache_do_get(xlo_fmt, c, offset, table,
+ true);
+}
+
+void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt, void **table)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_file_fmt_qcow_cache *c = qcow_data->l2_table_cache;
+ int i = __xloop_file_fmt_qcow_cache_get_table_idx(c, *table);
+
+ c->entries[i].ref--;
+ *table = NULL;
+
+ if (c->entries[i].ref == 0) {
+ c->entries[i].lru_counter = ++c->lru_counter;
+ }
+
+ ASSERT(c->entries[i].ref >= 0);
+}
diff --git a/src/kernel/xloop_file_fmt_qcow_cache.h b/src/kernel/xloop_file_fmt_qcow_cache.h
new file mode 100644
index 0000000..527d4ae
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_cache.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow_cache.h
+ *
+ * Ported QCOW2 implementation of the QEMU project (GPL-2.0):
+ * L2/refcount table cache for the QCOW2 format.
+ *
+ * The copyright (C) 2010 of the original code is owned by
+ * Kevin Wolf <kwolf@redhat.com>
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#ifndef _LINUX_XLOOP_FILE_FMT_QCOW_CACHE_H
+#define _LINUX_XLOOP_FILE_FMT_QCOW_CACHE_H
+
+#include "xloop_file_fmt.h"
+
+struct xloop_file_fmt_qcow_cache_table {
+ s64 offset;
+ u64 lru_counter;
+ int ref;
+ bool dirty;
+};
+
+struct xloop_file_fmt_qcow_cache {
+ struct xloop_file_fmt_qcow_cache_table *entries;
+ struct xloop_file_fmt_qcow_cache *depends;
+ int size;
+ int table_size;
+ bool depends_on_flush;
+ void *table_array;
+ u64 lru_counter;
+ u64 cache_clean_lru_counter;
+};
+
+extern struct xloop_file_fmt_qcow_cache *xloop_file_fmt_qcow_cache_create(
+ struct xloop_file_fmt *xlo_fmt,
+ int num_tables,
+ unsigned table_size);
+
+extern void xloop_file_fmt_qcow_cache_destroy(struct xloop_file_fmt *xlo_fmt);
+
+extern int xloop_file_fmt_qcow_cache_get(struct xloop_file_fmt *xlo_fmt,
+ u64 offset,
+ void **table);
+
+extern void xloop_file_fmt_qcow_cache_put(struct xloop_file_fmt *xlo_fmt,
+ void **table);
+
+#endif
diff --git a/src/kernel/xloop_file_fmt_qcow_cluster.c b/src/kernel/xloop_file_fmt_qcow_cluster.c
new file mode 100644
index 0000000..8394c76
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_cluster.c
@@ -0,0 +1,353 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow_cluster.c
+ *
+ * Ported QCOW2 implementation of the QEMU project (GPL-2.0):
+ * Cluster calculation and lookup for the QCOW2 format.
+ *
+ * The copyright (C) 2004-2006 of the original code is owned by Fabrice Bellard.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "xloop_file_fmt.h"
+#include "xloop_file_fmt_qcow_main.h"
+#include "xloop_file_fmt_qcow_cache.h"
+#include "xloop_file_fmt_qcow_cluster.h"
+
+/*
+ * __xloop_file_fmt_qcow_cluster_l2_load
+ *
+ * @xlo_fmt: QCOW file format
+ * @offset: A guest offset, used to calculate what slice of the L2
+ * table to load.
+ * @l2_offset: Offset to the L2 table in the image file.
+ * @l2_slice: Location to store the pointer to the L2 slice.
+ *
+ * Loads a L2 slice into memory (L2 slices are the parts of L2 tables
+ * that are loaded by the qcow2 cache). If the slice is in the cache,
+ * the cache is used; otherwise the L2 slice is loaded from the image
+ * file.
+ */
+static int __xloop_file_fmt_qcow_cluster_l2_load(struct xloop_file_fmt *xlo_fmt,
+ u64 offset, u64 l2_offset, u64 **l2_slice)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ int start_of_slice = xloop_file_fmt_qcow_l2_entry_size(qcow_data) * (
+ xloop_file_fmt_qcow_offset_to_l2_index(qcow_data, offset) -
+ xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset)
+ );
+
+ ASSERT(qcow_data->l2_table_cache != NULL);
+ return xloop_file_fmt_qcow_cache_get(xlo_fmt, l2_offset + start_of_slice,
+ (void **) l2_slice);
+}
+
+/*
+ * For a given L2 entry, count the number of contiguous subclusters of
+ * the same type starting from @sc_from. Compressed clusters are
+ * treated as if they were divided into subclusters of size
+ * qcow_data->subcluster_size.
+ *
+ * Return the number of contiguous subclusters and set @type to the
+ * subcluster type.
+ *
+ * If the L2 entry is invalid return -errno and set @type to
+ * QCOW_SUBCLUSTER_INVALID.
+ */
+static int __xloop_file_fmt_qcow_get_subcluster_range_type(
+ struct xloop_file_fmt *xlo_fmt, u64 l2_entry, u64 l2_bitmap,
+ unsigned int sc_from, enum xloop_file_fmt_qcow_subcluster_type *type)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ u32 val;
+
+ *type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry,
+ l2_bitmap, sc_from);
+
+ if (*type == QCOW_SUBCLUSTER_INVALID) {
+ return -EINVAL;
+ } else if (!xloop_file_fmt_qcow_has_subclusters(qcow_data) ||
+ *type == QCOW_SUBCLUSTER_COMPRESSED) {
+ return qcow_data->subclusters_per_cluster - sc_from;
+ }
+
+ switch (*type) {
+ case QCOW_SUBCLUSTER_NORMAL:
+ val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
+ return __builtin_ctz(~val) - sc_from;
+
+ case QCOW_SUBCLUSTER_ZERO_PLAIN:
+ case QCOW_SUBCLUSTER_ZERO_ALLOC:
+ val = (l2_bitmap | QCOW_OFLAG_SUB_ZERO_RANGE(0, sc_from)) >> 32;
+ return __builtin_ctz(~val) - sc_from;
+
+ case QCOW_SUBCLUSTER_UNALLOCATED_PLAIN:
+ case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC:
+ val = ((l2_bitmap >> 32) | l2_bitmap)
+ & ~QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
+ return __builtin_ctz(val) - sc_from;
+
+ default:
+ /* not reachable */
+ ASSERT(false);
+ *type = QCOW_SUBCLUSTER_INVALID;
+ return 0;
+ }
+}
+
+/*
+ * Return the number of contiguous subclusters of the exact same type
+ * in a given L2 slice, starting from cluster @l2_index, subcluster
+ * @sc_index. Allocated subclusters are required to be contiguous in
+ * the image file.
+ * At most @nb_clusters are checked (note that this means clusters,
+ * not subclusters).
+ * Compressed clusters are always processed one by one but for the
+ * purpose of this count they are treated as if they were divided into
+ * subclusters of size qcow_data->subcluster_size.
+ * On failure return -errno and update @l2_index to point to the
+ * invalid entry.
+ */
+static int __xloop_file_fmt_qcow_count_contiguous_subclusters(
+ struct xloop_file_fmt *xlo_fmt, int nb_clusters, unsigned int sc_index,
+ u64 *l2_slice, unsigned int *l2_index)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ int i, count = 0;
+ bool check_offset = false;
+ u64 expected_offset = 0;
+ enum xloop_file_fmt_qcow_subcluster_type expected_type =
+ QCOW_SUBCLUSTER_NORMAL;
+ enum xloop_file_fmt_qcow_subcluster_type type;
+
+ ASSERT(*l2_index + nb_clusters <= qcow_data->l2_slice_size);
+
+ for (i = 0; i < nb_clusters; i++) {
+ unsigned int first_sc = (i == 0) ? sc_index : 0;
+ u64 l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice,
+ *l2_index + i);
+ u64 l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice,
+ *l2_index + i);
+ int ret = __xloop_file_fmt_qcow_get_subcluster_range_type(xlo_fmt,
+ l2_entry, l2_bitmap, first_sc, &type);
+ if (ret < 0) {
+ *l2_index += i; /* Point to the invalid entry */
+ return -EIO;
+ }
+ if (i == 0) {
+ if (type == QCOW_SUBCLUSTER_COMPRESSED) {
+ /* Compressed clusters are always processed one by one */
+ return ret;
+ }
+ expected_type = type;
+ expected_offset = l2_entry & QCOW_L2E_OFFSET_MASK;
+ check_offset = (type == QCOW_SUBCLUSTER_NORMAL ||
+ type == QCOW_SUBCLUSTER_ZERO_ALLOC ||
+ type == QCOW_SUBCLUSTER_UNALLOCATED_ALLOC);
+ } else if (type != expected_type) {
+ break;
+ } else if (check_offset) {
+ expected_offset += qcow_data->cluster_size;
+ if (expected_offset != (l2_entry & QCOW_L2E_OFFSET_MASK)) {
+ break;
+ }
+ }
+ count += ret;
+ /* Stop if there are type changes before the end of the cluster */
+ if (first_sc + ret < qcow_data->subclusters_per_cluster) {
+ break;
+ }
+ }
+
+ return count;
+}
+
+/*
+ * xloop_file_fmt_qcow_get_host_offset
+ *
+ * For a given offset of the virtual disk find the equivalent host
+ * offset in the qcow2 file and store it in *host_offset. Neither
+ * offset needs to be aligned to a cluster boundary.
+ *
+ * If the cluster is unallocated then *host_offset will be 0.
+ * If the cluster is compressed then *host_offset will contain the
+ * complete compressed cluster descriptor.
+ *
+ * On entry, *bytes is the maximum number of contiguous bytes starting at
+ * offset that we are interested in.
+ *
+ * On exit, *bytes is the number of bytes starting at offset that have the same
+ * subcluster type and (if applicable) are stored contiguously in the image
+ * file. The subcluster type is stored in *subcluster_type.
+ * Compressed clusters are always processed one by one.
+ *
+ * Returns 0 on success, -errno in error cases.
+ */
+int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt,
+ u64 offset, unsigned int *bytes, u64 *host_offset,
+ enum xloop_file_fmt_qcow_subcluster_type *subcluster_type)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ unsigned int l2_index, sc_index;
+ u64 l1_index, l2_offset, *l2_slice, l2_entry, l2_bitmap;
+ int sc;
+ unsigned int offset_in_cluster;
+ u64 bytes_available, bytes_needed, nb_clusters;
+ enum xloop_file_fmt_qcow_subcluster_type type;
+ int ret;
+ u64 host_cluster_offset;
+
+ offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data,
+ offset);
+ bytes_needed = (u64) *bytes + offset_in_cluster;
+
+ /* compute how many bytes there are between the start of the cluster
+ * containing offset and the end of the l2 slice that contains
+ * the entry pointing to it */
+ bytes_available = ((u64)(
+ qcow_data->l2_slice_size -
+ xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data, offset))
+ ) << qcow_data->cluster_bits;
+
+ if (bytes_needed > bytes_available) {
+ bytes_needed = bytes_available;
+ }
+
+ *host_offset = 0;
+
+ /* seek to the l2 offset in the l1 table */
+ l1_index = xloop_file_fmt_qcow_offset_to_l1_index(qcow_data, offset);
+ if (l1_index >= qcow_data->l1_size) {
+ type = QCOW_SUBCLUSTER_UNALLOCATED_PLAIN;
+ goto out;
+ }
+
+ l2_offset = qcow_data->l1_table[l1_index] & QCOW_L1E_OFFSET_MASK;
+ if (!l2_offset) {
+ type = QCOW_SUBCLUSTER_UNALLOCATED_PLAIN;
+ goto out;
+ }
+
+ if (xloop_file_fmt_qcow_offset_into_cluster(qcow_data, l2_offset)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "L2 table offset "
+ "%llx unaligned (L1 index: %llx)", l2_offset, l1_index);
+ return -EIO;
+ }
+
+ /* load the l2 slice in memory */
+ ret = __xloop_file_fmt_qcow_cluster_l2_load(xlo_fmt, offset, l2_offset,
+ &l2_slice);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* find the cluster offset for the given disk offset */
+ l2_index = xloop_file_fmt_qcow_offset_to_l2_slice_index(qcow_data,
+ offset);
+ sc_index = xloop_file_fmt_qcow_offset_to_sc_index(qcow_data, offset);
+ l2_entry = xloop_file_fmt_qcow_get_l2_entry(qcow_data, l2_slice,
+ l2_index);
+ l2_bitmap = xloop_file_fmt_qcow_get_l2_bitmap(qcow_data, l2_slice,
+ l2_index);
+
+ nb_clusters = xloop_file_fmt_qcow_size_to_clusters(qcow_data,
+ bytes_needed);
+ /* bytes_needed <= *bytes + offset_in_cluster, both of which are
+ * unsigned integers; the minimum cluster size is 512, so this
+ * assertion is always true */
+ ASSERT(nb_clusters <= INT_MAX);
+
+ type = xloop_file_fmt_qcow_get_subcluster_type(xlo_fmt, l2_entry,
+ l2_bitmap, sc_index);
+ if (qcow_data->qcow_version < 3 && (
+ type == QCOW_SUBCLUSTER_ZERO_PLAIN ||
+ type == QCOW_SUBCLUSTER_ZERO_ALLOC)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "zero cluster "
+ "entry found in pre-v3 image (L2 offset: %llx, L2 index: %x)\n",
+ l2_offset, l2_index);
+ ret = -EIO;
+ goto fail;
+ }
+ switch (type) {
+ case QCOW_SUBCLUSTER_INVALID:
+ break; /* This is handled by count_contiguous_subclusters() below */
+ case QCOW_SUBCLUSTER_COMPRESSED:
+ if (xloop_file_fmt_qcow_has_data_file(qcow_data)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "compressed "
+ "cluster entry found in image with external data file "
+ "(L2 offset: %llx, L2 index: %x)\n", l2_offset, l2_index);
+ ret = -EIO;
+ goto fail;
+ }
+ *host_offset = l2_entry & QCOW_L2E_COMPRESSED_OFFSET_SIZE_MASK;
+ break;
+ case QCOW_SUBCLUSTER_ZERO_PLAIN:
+ case QCOW_SUBCLUSTER_UNALLOCATED_PLAIN:
+ break;
+ case QCOW_SUBCLUSTER_ZERO_ALLOC:
+ case QCOW_SUBCLUSTER_NORMAL:
+ case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC:
+ host_cluster_offset = l2_entry & QCOW_L2E_OFFSET_MASK;
+ *host_offset = host_cluster_offset + offset_in_cluster;
+ if (xloop_file_fmt_qcow_offset_into_cluster(qcow_data,
+ host_cluster_offset)) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "cluster "
+ "allocation offset %llx unaligned (L2 offset: %llx, "
+ "L2 index: %x)\n", host_cluster_offset, l2_offset, l2_index);
+ ret = -EIO;
+ goto fail;
+ }
+ if (xloop_file_fmt_qcow_has_data_file(qcow_data) &&
+ *host_offset != offset) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "external "
+ "data file host cluster offset %llx does not match guest "
+ "cluster offset: %llx, L2 index: %x)\n", host_cluster_offset,
+ offset - offset_in_cluster, l2_index);
+ ret = -EIO;
+ goto fail;
+ }
+ break;
+ default:
+ BUG();
+ }
+
+ sc = __xloop_file_fmt_qcow_count_contiguous_subclusters(xlo_fmt,
+ nb_clusters, sc_index, l2_slice, &l2_index);
+
+ if (sc < 0) {
+ dev_err_ratelimited(xloop_file_fmt_to_dev(xlo_fmt), "invalid cluster "
+ "entry found (L2 offset: %#llx, L2 index: %#x)", l2_offset,
+ l2_index);
+ ret = -EIO;
+ goto fail;
+ }
+ xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **) &l2_slice);
+
+ bytes_available = ((s64) sc + sc_index) << qcow_data->subcluster_bits;
+
+out:
+ if (bytes_available > bytes_needed) {
+ bytes_available = bytes_needed;
+ }
+
+ /* bytes_available <= bytes_needed <= *bytes + offset_in_cluster;
+ * subtracting offset_in_cluster will therefore definitely yield
+ * something not exceeding UINT_MAX */
+ ASSERT(bytes_available - offset_in_cluster <= UINT_MAX);
+ *bytes = bytes_available - offset_in_cluster;
+
+ *subcluster_type = type;
+
+ return 0;
+
+fail:
+ xloop_file_fmt_qcow_cache_put(xlo_fmt, (void **) &l2_slice);
+ return ret;
+}
diff --git a/src/kernel/xloop_file_fmt_qcow_cluster.h b/src/kernel/xloop_file_fmt_qcow_cluster.h
new file mode 100644
index 0000000..a3716f5
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_cluster.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow_cluster.h
+ *
+ * Ported QCOW2 implementation of the QEMU project (GPL-2.0):
+ * Cluster calculation and lookup for the QCOW2 format.
+ *
+ * The copyright (C) 2004-2006 of the original code is owned by Fabrice Bellard.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#ifndef _LINUX_XLOOP_FILE_FMT_QCOW_CLUSTER_H
+#define _LINUX_XLOOP_FILE_FMT_QCOW_CLUSTER_H
+
+#include "xloop_file_fmt.h"
+
+extern int xloop_file_fmt_qcow_get_host_offset(struct xloop_file_fmt *xlo_fmt,
+ u64 offset, unsigned int *bytes, u64 *host_offset,
+ enum xloop_file_fmt_qcow_subcluster_type *subcluster_type);
+
+#endif
diff --git a/src/kernel/xloop_file_fmt_qcow_main.c b/src/kernel/xloop_file_fmt_qcow_main.c
new file mode 100644
index 0000000..38fe1af
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_main.c
@@ -0,0 +1,1283 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow.c
+ *
+ * QCOW file format driver for the xloop device module.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/limits.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/bvec.h>
+#include <linux/mutex.h>
+#include <linux/uio.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/zlib.h>
+#ifdef CONFIG_ZSTD_DECOMPRESS
+#include <linux/zstd.h>
+#endif
+
+#include "xloop_file_fmt.h"
+#include "xloop_file_fmt_qcow_main.h"
+#include "xloop_file_fmt_qcow_cache.h"
+#include "xloop_file_fmt_qcow_cluster.h"
+
+#ifdef CONFIG_ZSTD_DECOMPRESS
+#define ZSTD_WINDOWLOG_LIMIT_DEFAULT 27
+#define ZSTD_MAXWINDOWSIZE ((U32_C(1) << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
+#endif
+
+typedef ssize_t (*qcow_file_fmt_decompress_fn)(struct xloop_file_fmt *xlo_fmt,
+ void *dest, size_t dest_size, const void *src, size_t src_size);
+
+static int __qcow_file_fmt_header_read(struct xloop_file_fmt *xlo_fmt,
+ struct file *file, struct xloop_file_fmt_qcow_header *header)
+{
+ ssize_t len;
+ loff_t offset;
+ int ret = 0;
+
+ /* read QCOW header */
+ offset = 0;
+ len = kernel_read(file, header, sizeof(*header), &offset);
+ if (len < 0) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read QCOW "
+ "header\n");
+ return len;
+ }
+
+ header->magic = be32_to_cpu(header->magic);
+ header->version = be32_to_cpu(header->version);
+ header->backing_file_offset = be64_to_cpu(header->backing_file_offset);
+ header->backing_file_size = be32_to_cpu(header->backing_file_size);
+ header->cluster_bits = be32_to_cpu(header->cluster_bits);
+ header->size = be64_to_cpu(header->size);
+ header->crypt_method = be32_to_cpu(header->crypt_method);
+ header->l1_size = be32_to_cpu(header->l1_size);
+ header->l1_table_offset = be64_to_cpu(header->l1_table_offset);
+ header->refcount_table_offset =
+ be64_to_cpu(header->refcount_table_offset);
+ header->refcount_table_clusters =
+ be32_to_cpu(header->refcount_table_clusters);
+ header->nb_snapshots = be32_to_cpu(header->nb_snapshots);
+ header->snapshots_offset = be64_to_cpu(header->snapshots_offset);
+
+ /* check QCOW file format and header version */
+ if (header->magic != QCOW_MAGIC) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is not in QCOW "
+ "format\n");
+ return -EINVAL;
+ }
+
+ if (header->version < 2 || header->version > 3) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported QCOW "
+ "version %d\n", header->version);
+ return -ENOTSUPP;
+ }
+
+ /* initialize version 3 header fields */
+ if (header->version == 2) {
+ header->incompatible_features = 0;
+ header->compatible_features = 0;
+ header->autoclear_features = 0;
+ header->refcount_order = 4;
+ header->header_length = 72;
+ } else {
+ header->incompatible_features =
+ be64_to_cpu(header->incompatible_features);
+ header->compatible_features =
+ be64_to_cpu(header->compatible_features);
+ header->autoclear_features =
+ be64_to_cpu(header->autoclear_features);
+ header->refcount_order = be32_to_cpu(header->refcount_order);
+ header->header_length = be32_to_cpu(header->header_length);
+
+ if (header->header_length < 104) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "QCOW header too short\n");
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int __qcow_file_fmt_validate_table(struct xloop_file_fmt *xlo_fmt,
+ u64 offset, u64 entries, size_t entry_len, s64 max_size_bytes,
+ const char *table_name)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ if (entries > max_size_bytes / entry_len) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "%s too large\n", table_name);
+ return -EFBIG;
+ }
+
+ /* Use signed S64_MAX as the maximum even for u64 header fields,
+ * because values will be passed to qemu functions taking s64. */
+ if ((S64_MAX - entries * entry_len < offset) || (
+ xloop_file_fmt_qcow_offset_into_cluster(qcow_data, offset) != 0)
+ ) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "%s offset invalid",
+ table_name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline loff_t __qcow_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ return ((loff_t) blk_rq_pos(rq) << 9) + xlo->xlo_offset;
+}
+
+static int __qcow_file_fmt_compression_init(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ int ret = 0;
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ size_t workspace_size;
+#endif
+
+ /* create workspace for ZLIB decompression stream */
+ qcow_data->zlib_dstrm = kzalloc(sizeof(*qcow_data->zlib_dstrm), GFP_KERNEL);
+ if (!qcow_data->zlib_dstrm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ qcow_data->zlib_dstrm->workspace = vzalloc(zlib_inflate_workspacesize());
+ if (!qcow_data->zlib_dstrm->workspace) {
+ ret = -ENOMEM;
+ goto out_free_zlib_dstrm;
+ }
+
+ /* set up ZLIB decompression stream */
+ ret = zlib_inflateInit2(qcow_data->zlib_dstrm, -12);
+ if (ret != Z_OK) {
+ ret = -EIO;
+ goto out_free_zlib_dworkspace;
+ }
+
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ /* create workspace for ZSTD decompression stream */
+ workspace_size = ZSTD_DStreamWorkspaceBound(ZSTD_MAXWINDOWSIZE);
+ qcow_data->zstd_dworkspace = vzalloc(workspace_size);
+ if (!qcow_data->zstd_dworkspace) {
+ ret = -ENOMEM;
+ goto out_free_zlib_dworkspace;
+ }
+
+ /* set up ZSTD decompression stream */
+ qcow_data->zstd_dstrm = ZSTD_initDStream(ZSTD_MAXWINDOWSIZE,
+ qcow_data->zstd_dworkspace, workspace_size);
+ if (!qcow_data->zstd_dstrm) {
+ ret = -EINVAL;
+ goto out_free_zstd_dworkspace;
+ }
+#endif
+
+ /* create cache for last compressed QCOW cluster */
+ qcow_data->cmp_last_coffset = ULLONG_MAX;
+ qcow_data->cmp_out_buf = vmalloc(qcow_data->cluster_size);
+ if (!qcow_data->cmp_out_buf) {
+ ret = -ENOMEM;
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ goto out_free_zstd_dworkspace;
+#else
+ goto out_free_zlib_dworkspace;
+#endif
+ }
+
+ return ret;
+
+#ifdef CONFIG_ZSTD_DECOMPRESS
+out_free_zstd_dworkspace:
+ vfree(qcow_data->zstd_dworkspace);
+#endif
+out_free_zlib_dworkspace:
+ vfree(qcow_data->zlib_dstrm->workspace);
+out_free_zlib_dstrm:
+ kfree(qcow_data->zlib_dstrm);
+out:
+ return ret;
+}
+
+static void __qcow_file_fmt_compression_exit(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ /* ZLIB specific cleanup */
+ zlib_inflateEnd(qcow_data->zlib_dstrm);
+ vfree(qcow_data->zlib_dstrm->workspace);
+ kfree(qcow_data->zlib_dstrm);
+
+ /* ZSTD specific cleanup */
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ vfree(qcow_data->zstd_dworkspace);
+#endif
+
+ /* last compressed QCOW cluster cleanup */
+ vfree(qcow_data->cmp_out_buf);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void __qcow_file_fmt_header_to_buf(struct xloop_file_fmt *xlo_fmt,
+ const struct xloop_file_fmt_qcow_header *header)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ char *header_buf = qcow_data->dbgfs_file_qcow_header_buf;
+ ssize_t len = 0;
+
+ len += sprintf(header_buf + len, "magic: %d\n",
+ header->magic);
+ len += sprintf(header_buf + len, "version: %d\n",
+ header->version);
+ len += sprintf(header_buf + len, "backing_file_offset: %lld\n",
+ header->backing_file_offset);
+ len += sprintf(header_buf + len, "backing_file_size: %d\n",
+ header->backing_file_size);
+ len += sprintf(header_buf + len, "cluster_bits: %d\n",
+ header->cluster_bits);
+ len += sprintf(header_buf + len, "size: %lld\n",
+ header->size);
+ len += sprintf(header_buf + len, "crypt_method: %d\n",
+ header->crypt_method);
+ len += sprintf(header_buf + len, "l1_size: %d\n",
+ header->l1_size);
+ len += sprintf(header_buf + len, "l1_table_offset: %lld\n",
+ header->l1_table_offset);
+ len += sprintf(header_buf + len, "refcount_table_offset: %lld\n",
+ header->refcount_table_offset);
+ len += sprintf(header_buf + len, "refcount_table_clusters: %d\n",
+ header->refcount_table_clusters);
+ len += sprintf(header_buf + len, "nb_snapshots: %d\n",
+ header->nb_snapshots);
+ len += sprintf(header_buf + len, "snapshots_offset: %lld\n",
+ header->snapshots_offset);
+
+ if (header->version == 3) {
+ len += sprintf(header_buf + len,
+ "incompatible_features: %lld\n",
+ header->incompatible_features);
+ len += sprintf(header_buf + len,
+ "compatible_features: %lld\n",
+ header->compatible_features);
+ len += sprintf(header_buf + len,
+ "autoclear_features: %lld\n",
+ header->autoclear_features);
+ len += sprintf(header_buf + len,
+ "refcount_order: %d\n",
+ header->refcount_order);
+ len += sprintf(header_buf + len,
+ "header_length: %d\n",
+ header->header_length);
+ }
+
+ if (header->header_length > offsetof(struct xloop_file_fmt_qcow_header,
+ compression_type)) {
+ len += sprintf(header_buf + len,
+ "compression_type: %d\n",
+ header->compression_type);
+ }
+
+ ASSERT(len < QCOW_HEADER_BUF_LEN);
+}
+
+static ssize_t __qcow_file_fmt_dbgfs_hdr_read(struct file *file,
+ char __user *buf, size_t size, loff_t *ppos)
+{
+ struct xloop_file_fmt *xlo_fmt = file->private_data;
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ char *header_buf = qcow_data->dbgfs_file_qcow_header_buf;
+
+ return simple_read_from_buffer(buf, size, ppos, header_buf,
+ strlen(header_buf));
+}
+
+static const struct file_operations qcow_file_fmt_dbgfs_hdr_fops = {
+ .open = simple_open,
+ .read = __qcow_file_fmt_dbgfs_hdr_read
+};
+
+static ssize_t __qcow_file_fmt_dbgfs_ofs_read(struct file *file,
+ char __user *buf, size_t size, loff_t *ppos)
+{
+ struct xloop_file_fmt *xlo_fmt = file->private_data;
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ unsigned int cur_bytes = 1;
+ u64 offset = 0;
+ u64 coffset = 0;
+ u64 host_offset = 0;
+ s64 offset_in_cluster = 0;
+ enum xloop_file_fmt_qcow_subcluster_type type;
+ ssize_t len = 0;
+ int ret = 0, csize = 0, nb_csectors = 0;
+
+ /* read the share debugfs offset */
+ ret = mutex_lock_interruptible(&qcow_data->dbgfs_qcow_offset_mutex);
+ if (ret)
+ return ret;
+
+ offset = qcow_data->dbgfs_qcow_offset;
+ mutex_unlock(&qcow_data->dbgfs_qcow_offset_mutex);
+
+ /* calculate and print the cluster offset */
+ ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt,
+ offset, &cur_bytes, &host_offset, &type);
+ if (ret < 0)
+ return -EINVAL;
+
+ offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(qcow_data,
+ offset);
+
+ len = sprintf(qcow_data->dbgfs_file_qcow_cluster_buf,
+ "cluster type: %s\n"
+ "cluster offset host: %lld\n"
+ "cluster offset guest: %lld\n"
+ "cluster offset in-cluster: %lld\n",
+ xloop_file_fmt_qcow_get_subcluster_name(type),
+ host_offset, offset, offset_in_cluster);
+
+ if (type == QCOW_SUBCLUSTER_COMPRESSED) {
+ coffset = host_offset & qcow_data->cluster_offset_mask;
+ nb_csectors = ((host_offset >> qcow_data->csize_shift) &
+ qcow_data->csize_mask) + 1;
+ csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE -
+ (coffset & ~QCOW_COMPRESSED_SECTOR_MASK);
+
+ len += sprintf(qcow_data->dbgfs_file_qcow_cluster_buf + len,
+ "cluster compressed offset: %lld\n"
+ "cluster compressed sectors: %d\n"
+ "cluster compressed size: %d\n",
+ coffset, nb_csectors, csize);
+ }
+
+ ASSERT(len < QCOW_CLUSTER_BUF_LEN);
+
+ return simple_read_from_buffer(buf, size, ppos,
+ qcow_data->dbgfs_file_qcow_cluster_buf, len);
+}
+
+static ssize_t __qcow_file_fmt_dbgfs_ofs_write(struct file *file,
+ const char __user *buf, size_t size, loff_t *ppos)
+{
+ struct xloop_file_fmt *xlo_fmt = file->private_data;
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ ssize_t len = 0;
+ int ret = 0;
+
+ if (*ppos > QCOW_OFFSET_BUF_LEN || size > QCOW_OFFSET_BUF_LEN)
+ return -EINVAL;
+
+ len = simple_write_to_buffer(qcow_data->dbgfs_file_qcow_offset_buf,
+ QCOW_OFFSET_BUF_LEN, ppos, buf, size);
+ if (len < 0)
+ return len;
+
+ qcow_data->dbgfs_file_qcow_offset_buf[len] = '\0';
+
+ ret = mutex_lock_interruptible(&qcow_data->dbgfs_qcow_offset_mutex);
+ if (ret)
+ return ret;
+
+ ret = kstrtou64(qcow_data->dbgfs_file_qcow_offset_buf, 10,
+ &qcow_data->dbgfs_qcow_offset);
+ if (ret < 0)
+ goto out;
+
+ ret = len;
+out:
+ mutex_unlock(&qcow_data->dbgfs_qcow_offset_mutex);
+ return ret;
+}
+
+static const struct file_operations qcow_file_fmt_dbgfs_ofs_fops = {
+ .open = simple_open,
+ .read = __qcow_file_fmt_dbgfs_ofs_read,
+ .write = __qcow_file_fmt_dbgfs_ofs_write
+};
+
+static int __qcow_file_fmt_dbgfs_init(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ int ret = 0;
+
+ qcow_data->dbgfs_dir = debugfs_create_dir("QCOW", xlo->xlo_dbgfs_dir);
+ if (IS_ERR_OR_NULL(qcow_data->dbgfs_dir)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ qcow_data->dbgfs_file_qcow_header = debugfs_create_file("header",
+ S_IRUGO, qcow_data->dbgfs_dir, xlo_fmt,
+ &qcow_file_fmt_dbgfs_hdr_fops);
+ if (IS_ERR_OR_NULL(qcow_data->dbgfs_file_qcow_header)) {
+ ret = -ENODEV;
+ goto out_free_dbgfs_dir;
+ }
+
+ qcow_data->dbgfs_file_qcow_offset = debugfs_create_file("offset",
+ S_IRUGO | S_IWUSR, qcow_data->dbgfs_dir, xlo_fmt,
+ &qcow_file_fmt_dbgfs_ofs_fops);
+ if (IS_ERR_OR_NULL(qcow_data->dbgfs_file_qcow_offset)) {
+ qcow_data->dbgfs_file_qcow_offset = NULL;
+ ret = -ENODEV;
+ goto out_free_dbgfs_hdr;
+ }
+
+ qcow_data->dbgfs_qcow_offset = 0;
+ mutex_init(&qcow_data->dbgfs_qcow_offset_mutex);
+
+ return ret;
+
+out_free_dbgfs_hdr:
+ debugfs_remove(qcow_data->dbgfs_file_qcow_header);
+ qcow_data->dbgfs_file_qcow_header = NULL;
+out_free_dbgfs_dir:
+ debugfs_remove(qcow_data->dbgfs_dir);
+ qcow_data->dbgfs_dir = NULL;
+out:
+ return ret;
+}
+
+static void __qcow_file_fmt_dbgfs_exit(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ if (qcow_data->dbgfs_file_qcow_offset)
+ debugfs_remove(qcow_data->dbgfs_file_qcow_offset);
+
+ mutex_destroy(&qcow_data->dbgfs_qcow_offset_mutex);
+
+ if (qcow_data->dbgfs_file_qcow_header)
+ debugfs_remove(qcow_data->dbgfs_file_qcow_header);
+
+ if (qcow_data->dbgfs_dir)
+ debugfs_remove(qcow_data->dbgfs_dir);
+}
+#endif
+
+static int __qcow_file_fmt_validate_compression_type(
+ struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ switch (qcow_data->compression_type) {
+ case QCOW_COMPRESSION_TYPE_ZLIB:
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ case QCOW_COMPRESSION_TYPE_ZSTD:
+#endif
+ break;
+ default:
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unknown compression type: %u",
+ qcow_data->compression_type);
+ return -ENOTSUPP;
+ }
+
+ /*
+ * if the compression type differs from QCOW_COMPRESSION_TYPE_ZLIB
+ * the incompatible feature flag must be set
+ */
+ if (qcow_data->compression_type == QCOW_COMPRESSION_TYPE_ZLIB) {
+ if (qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "compression type "
+ "incompatible feature bit must not be set\n");
+ return -EINVAL;
+ }
+ } else {
+ if (!(qcow_data->incompatible_features & QCOW_INCOMPAT_COMPRESSION)) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "compression type "
+ "incompatible feature bit must be set\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int qcow_file_fmt_init(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data;
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ struct xloop_file_fmt_qcow_header header;
+ u64 l1_vm_state_index;
+ u64 l2_cache_size;
+ u64 l2_cache_entry_size;
+ u64 virtual_disk_size;
+ u64 max_l2_entries;
+ u64 max_l2_cache;
+ u64 l2_cache_max_setting;
+ ssize_t len;
+ unsigned int i;
+ int ret = 0;
+
+ /* allocate memory for saving QCOW file format data */
+ qcow_data = kzalloc(sizeof(*qcow_data), GFP_KERNEL);
+ if (!qcow_data)
+ return -ENOMEM;
+
+ xlo_fmt->private_data = qcow_data;
+
+ /* read the QCOW file header */
+ ret = __qcow_file_fmt_header_read(xlo_fmt, xlo->xlo_backing_file, &header);
+ if (ret)
+ goto free_qcow_data;
+
+ /* save information of the header fields in human readable format in
+ * a file buffer to access it with debugfs */
+#ifdef CONFIG_DEBUG_FS
+ __qcow_file_fmt_header_to_buf(xlo_fmt, &header);
+#endif
+
+ qcow_data->qcow_version = header.version;
+
+ /* Initialise cluster size */
+ if (header.cluster_bits < QCOW_MIN_CLUSTER_BITS
+ || header.cluster_bits > QCOW_MAX_CLUSTER_BITS) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported cluster size: "
+ "2^%d\n", header.cluster_bits);
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ qcow_data->cluster_bits = header.cluster_bits;
+ qcow_data->cluster_size = 1 << qcow_data->cluster_bits;
+
+ if (header.header_length > qcow_data->cluster_size) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "QCOW header exceeds cluster "
+ "size\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ if (header.backing_file_offset > qcow_data->cluster_size) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "invalid backing file "
+ "offset\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ if (header.backing_file_offset) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "backing file support not "
+ "available\n");
+ ret = -ENOTSUPP;
+ goto free_qcow_data;
+ }
+
+ /* handle feature bits */
+ qcow_data->incompatible_features = header.incompatible_features;
+ qcow_data->compatible_features = header.compatible_features;
+ qcow_data->autoclear_features = header.autoclear_features;
+
+ /*
+ * Handle compression type
+ * Older qcow2 images don't contain the compression type header.
+ * Distinguish them by the header length and use
+ * the only valid (default) compression type in that case
+ */
+ if (header.header_length > offsetof(struct xloop_file_fmt_qcow_header,
+ compression_type)) {
+ qcow_data->compression_type = header.compression_type;
+ } else {
+ qcow_data->compression_type = QCOW_COMPRESSION_TYPE_ZLIB;
+ }
+
+ ret = __qcow_file_fmt_validate_compression_type(xlo_fmt);
+ if (ret) {
+ goto free_qcow_data;
+ }
+
+ /* check for incompatible features */
+ if (qcow_data->incompatible_features & QCOW_INCOMPAT_DIRTY) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image contains inconsistent "
+ "refcounts\n");
+ ret = -EACCES;
+ goto free_qcow_data;
+ }
+
+ if (qcow_data->incompatible_features & QCOW_INCOMPAT_CORRUPT) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is corrupt; cannot be "
+ "opened read/write\n");
+ ret = -EACCES;
+ goto free_qcow_data;
+ }
+
+ if (qcow_data->incompatible_features & QCOW_INCOMPAT_DATA_FILE) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "data-file is required for "
+ "this image\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ qcow_data->subclusters_per_cluster =
+ xloop_file_fmt_qcow_has_subclusters(qcow_data) ?
+ QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER : 1;
+ qcow_data->subcluster_size =
+ qcow_data->cluster_size / qcow_data->subclusters_per_cluster;
+ /*
+ * check if subcluster_size is non-zero to avoid unknown results of
+ * __builtin_ctz
+ */
+ ASSERT(qcow_data->subcluster_size != 0);
+ qcow_data->subcluster_bits = __builtin_ctz(qcow_data->subcluster_size);
+
+ if (qcow_data->subcluster_size < (1 << QCOW_MIN_CLUSTER_BITS)) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "unsupported subcluster "
+ "size: %d\n", qcow_data->subcluster_size);
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ /* Check support for various header values */
+ if (header.refcount_order > 6) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "reference count entry width "
+ "too large; may not exceed 64 bits\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+ qcow_data->refcount_order = header.refcount_order;
+ qcow_data->refcount_bits = 1 << qcow_data->refcount_order;
+ qcow_data->refcount_max = U64_C(1) << (qcow_data->refcount_bits - 1);
+ qcow_data->refcount_max += qcow_data->refcount_max - 1;
+
+ qcow_data->crypt_method_header = header.crypt_method;
+ if (qcow_data->crypt_method_header) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "encryption support not "
+ "available\n");
+ ret = -ENOTSUPP;
+ goto free_qcow_data;
+ }
+
+ /*
+ * check if xloop_file_fmt_qcow_l2_entry_size(qcow_data) is non-zero to
+ * avoid unknown results of __builtin_ctz
+ */
+ ASSERT(xloop_file_fmt_qcow_l2_entry_size(qcow_data) != 0);
+ qcow_data->l2_bits = qcow_data->cluster_bits -
+ __builtin_ctz(xloop_file_fmt_qcow_l2_entry_size(qcow_data));
+ qcow_data->l2_size = 1 << qcow_data->l2_bits;
+ /* 2^(qcow_data->refcount_order - 3) is the refcount width in bytes */
+ qcow_data->refcount_block_bits = qcow_data->cluster_bits -
+ (qcow_data->refcount_order - 3);
+ qcow_data->refcount_block_size = 1 << qcow_data->refcount_block_bits;
+ qcow_data->size = header.size;
+ qcow_data->csize_shift = (62 - (qcow_data->cluster_bits - 8));
+ qcow_data->csize_mask = (1 << (qcow_data->cluster_bits - 8)) - 1;
+ qcow_data->cluster_offset_mask = (1LL << qcow_data->csize_shift) - 1;
+
+ qcow_data->refcount_table_offset = header.refcount_table_offset;
+ qcow_data->refcount_table_size = header.refcount_table_clusters <<
+ (qcow_data->cluster_bits - 3);
+
+ if (header.refcount_table_clusters == 0) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image does not contain a "
+ "reference count table\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ ret = __qcow_file_fmt_validate_table(xlo_fmt,
+ qcow_data->refcount_table_offset,
+ header.refcount_table_clusters, qcow_data->cluster_size,
+ QCOW_MAX_REFTABLE_SIZE, "Reference count table");
+ if (ret < 0) {
+ goto free_qcow_data;
+ }
+
+ /* The total size in bytes of the snapshot table is checked in
+ * qcow2_read_snapshots() because the size of each snapshot is
+ * variable and we don't know it yet.
+ * Here we only check the offset and number of snapshots. */
+ ret = __qcow_file_fmt_validate_table(xlo_fmt, header.snapshots_offset,
+ header.nb_snapshots,
+ sizeof(struct xloop_file_fmt_qcow_snapshot_header),
+ sizeof(struct xloop_file_fmt_qcow_snapshot_header) *
+ QCOW_MAX_SNAPSHOTS, "Snapshot table");
+ if (ret < 0) {
+ goto free_qcow_data;
+ }
+
+ /* read the level 1 table */
+ ret = __qcow_file_fmt_validate_table(xlo_fmt, header.l1_table_offset,
+ header.l1_size, QCOW_L1E_SIZE, QCOW_MAX_L1_SIZE,
+ "Active L1 table");
+ if (ret < 0) {
+ goto free_qcow_data;
+ }
+ qcow_data->l1_size = header.l1_size;
+ qcow_data->l1_table_offset = header.l1_table_offset;
+
+ l1_vm_state_index = xloop_file_fmt_qcow_size_to_l1(qcow_data,
+ header.size);
+ if (l1_vm_state_index > INT_MAX) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "image is too big\n");
+ ret = -EFBIG;
+ goto free_qcow_data;
+ }
+ qcow_data->l1_vm_state_index = l1_vm_state_index;
+
+ /* the L1 table must contain at least enough entries to put header.size
+ * bytes */
+ if (qcow_data->l1_size < qcow_data->l1_vm_state_index) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "L1 table is too small\n");
+ ret = -EINVAL;
+ goto free_qcow_data;
+ }
+
+ if (qcow_data->l1_size > 0) {
+ qcow_data->l1_table = vzalloc(round_up(qcow_data->l1_size *
+ QCOW_L1E_SIZE, 512));
+ if (qcow_data->l1_table == NULL) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not allocate "
+ "L1 table\n");
+ ret = -ENOMEM;
+ goto free_qcow_data;
+ }
+ len = kernel_read(xlo->xlo_backing_file, qcow_data->l1_table,
+ qcow_data->l1_size * QCOW_L1E_SIZE,
+ &qcow_data->l1_table_offset);
+ if (len < 0) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "could not read "
+ "L1 table\n");
+ ret = len;
+ goto free_l1_table;
+ }
+ for (i = 0; i < qcow_data->l1_size; i++) {
+ qcow_data->l1_table[i] =
+ be64_to_cpu(qcow_data->l1_table[i]);
+ }
+ }
+
+ /* Internal snapshots */
+ qcow_data->snapshots_offset = header.snapshots_offset;
+ qcow_data->nb_snapshots = header.nb_snapshots;
+
+ if (qcow_data->nb_snapshots > 0) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "snapshots support not "
+ "available\n");
+ ret = -ENOTSUPP;
+ goto free_l1_table;
+ }
+
+ /* create cache for L2 */
+ virtual_disk_size = qcow_data->size;
+ max_l2_entries = DIV_ROUND_UP(virtual_disk_size, qcow_data->cluster_size);
+ max_l2_cache = round_up(
+ max_l2_entries * xloop_file_fmt_qcow_l2_entry_size(qcow_data),
+ qcow_data->cluster_size);
+
+ /* define the maximum L2 cache size */
+ l2_cache_max_setting = QCOW_DEFAULT_L2_CACHE_MAX_SIZE;
+
+ /* limit the L2 cache size to maximum l2_cache_max_setting */
+ l2_cache_size = min(max_l2_cache, l2_cache_max_setting);
+
+ /* determine the size of a cache entry */
+ l2_cache_entry_size = min(qcow_data->cluster_size, (int)PAGE_SIZE);
+
+ /* calculate the number of cache tables */
+ l2_cache_size /= l2_cache_entry_size;
+ if (l2_cache_size < QCOW_MIN_L2_CACHE_SIZE) {
+ l2_cache_size = QCOW_MIN_L2_CACHE_SIZE;
+ }
+
+ if (l2_cache_size > INT_MAX) {
+ dev_err(xloop_file_fmt_to_dev(xlo_fmt), "L2 cache size too big\n");
+ ret = -EINVAL;
+ goto free_l1_table;
+ }
+
+ qcow_data->l2_slice_size =
+ l2_cache_entry_size / xloop_file_fmt_qcow_l2_entry_size(qcow_data);
+
+ qcow_data->l2_table_cache = xloop_file_fmt_qcow_cache_create(xlo_fmt,
+ l2_cache_size, l2_cache_entry_size);
+ if (!qcow_data->l2_table_cache) {
+ ret = -ENOMEM;
+ goto free_l1_table;
+ }
+
+ /* initialize compression support */
+ ret = __qcow_file_fmt_compression_init(xlo_fmt);
+ if (ret < 0)
+ goto free_l2_cache;
+
+ /* initialize debugfs entries */
+#ifdef CONFIG_DEBUG_FS
+ ret = __qcow_file_fmt_dbgfs_init(xlo_fmt);
+ if (ret < 0)
+ goto free_l2_cache;
+#endif
+
+ return ret;
+
+free_l2_cache:
+ xloop_file_fmt_qcow_cache_destroy(xlo_fmt);
+free_l1_table:
+ vfree(qcow_data->l1_table);
+free_qcow_data:
+ kfree(qcow_data);
+ xlo_fmt->private_data = NULL;
+ return ret;
+}
+
+static void qcow_file_fmt_exit(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+#ifdef CONFIG_DEBUG_FS
+ __qcow_file_fmt_dbgfs_exit(xlo_fmt);
+#endif
+
+ __qcow_file_fmt_compression_exit(xlo_fmt);
+
+ if (qcow_data->l1_table) {
+ vfree(qcow_data->l1_table);
+ }
+
+ if (qcow_data->l2_table_cache) {
+ xloop_file_fmt_qcow_cache_destroy(xlo_fmt);
+ }
+
+ if (qcow_data) {
+ kfree(qcow_data);
+ xlo_fmt->private_data = NULL;
+ }
+}
+
+/*
+ * __qcow_file_fmt_zlib_decompress()
+ *
+ * Decompress some data (not more than @src_size bytes) to produce exactly
+ * @dest_size bytes using zlib compression method
+ *
+ * @xlo_fmt - QCOW file format
+ * @dest - destination buffer, @dest_size bytes
+ * @src - source buffer, @src_size bytes
+ *
+ * Returns: 0 on success
+ * -EIO on fail
+ */
+static ssize_t __qcow_file_fmt_zlib_decompress(struct xloop_file_fmt *xlo_fmt,
+ void *dest,
+ size_t dest_size,
+ const void *src,
+ size_t src_size)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ u8 zerostuff = 0;
+ ssize_t ret = 0;
+
+ ret = zlib_inflateReset(qcow_data->zlib_dstrm);
+ if (ret != Z_OK) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ qcow_data->zlib_dstrm->avail_in = src_size;
+ qcow_data->zlib_dstrm->next_in = (void *)src;
+ qcow_data->zlib_dstrm->avail_out = dest_size;
+ qcow_data->zlib_dstrm->next_out = dest;
+
+ ret = zlib_inflate(qcow_data->zlib_dstrm, Z_SYNC_FLUSH);
+ /*
+ * Work around a bug in zlib, which sometimes wants to taste an extra
+ * byte when being used in the (undocumented) raw deflate mode.
+ * (From USAGI).
+ */
+ if (ret == Z_OK && !qcow_data->zlib_dstrm->avail_in &&
+ qcow_data->zlib_dstrm->avail_out) {
+ qcow_data->zlib_dstrm->next_in = &zerostuff;
+ qcow_data->zlib_dstrm->avail_in = 1;
+ ret = zlib_inflate(qcow_data->zlib_dstrm, Z_FINISH);
+ }
+ if (ret != Z_STREAM_END) {
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+#ifdef CONFIG_ZSTD_DECOMPRESS
+/*
+ * __qcow_file_fmt_zstd_decompress()
+ *
+ * Decompress some data (not more than @src_size bytes) to produce exactly
+ * @dest_size bytes using zstd compression method
+ *
+ * @xlo_fmt - QCOW file format
+ * @dest - destination buffer, @dest_size bytes
+ * @src - source buffer, @src_size bytes
+ *
+ * Returns: 0 on success
+ * -EIO on any error
+ */
+static ssize_t __qcow_file_fmt_zstd_decompress(struct xloop_file_fmt *xlo_fmt,
+ void *dest,
+ size_t dest_size,
+ const void *src,
+ size_t src_size)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ size_t zstd_ret = 0;
+ ssize_t ret = 0;
+
+ ZSTD_outBuffer output = {
+ .dst = dest,
+ .size = dest_size,
+ .pos = 0
+ };
+
+ ZSTD_inBuffer input = {
+ .src = src,
+ .size = src_size,
+ .pos = 0
+ };
+
+ zstd_ret = ZSTD_resetDStream(qcow_data->zstd_dstrm);
+
+ if (ZSTD_isError(zstd_ret)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /*
+ * The compressed stream from the input buffer may consist of more
+ * than one zstd frame. So we iterate until we get a fully
+ * uncompressed cluster.
+ * From zstd docs related to ZSTD_decompressStream:
+ * "return : 0 when a frame is completely decoded and fully flushed"
+ * We suppose that this means: each time ZSTD_decompressStream reads
+ * only ONE full frame and returns 0 if and only if that frame
+ * is completely decoded and flushed. Only after returning 0,
+ * ZSTD_decompressStream reads another ONE full frame.
+ */
+ while (output.pos < output.size) {
+ size_t last_in_pos = input.pos;
+ size_t last_out_pos = output.pos;
+ zstd_ret = ZSTD_decompressStream(qcow_data->zstd_dstrm, &output, &input);
+
+ if (ZSTD_isError(zstd_ret)) {
+ ret = -EIO;
+ break;
+ }
+
+ /*
+ * The ZSTD manual is vague about what to do if it reads
+ * the buffer partially, and we don't want to get stuck
+ * in an infinite loop where ZSTD_decompressStream
+ * returns > 0 waiting for another input chunk. So, we add
+ * a check which ensures that the loop makes some progress
+ * on each step.
+ */
+ if (last_in_pos >= input.pos &&
+ last_out_pos >= output.pos) {
+ ret = -EIO;
+ break;
+ }
+ }
+ /*
+ * Make sure that we have the frame fully flushed here
+ * if not, we somehow managed to get uncompressed cluster
+ * greater then the cluster size, possibly because of its
+ * damage.
+ */
+ if (zstd_ret > 0) {
+ ret = -EIO;
+ }
+
+out:
+ ASSERT(ret == 0 || ret == -EIO);
+ return ret;
+}
+#endif
+
+/*
+ * __qcow_file_fmt_buffer_decompress()
+ *
+ * Decompress @src_size bytes of data using the compression
+ * method defined by the image compression type
+ *
+ * @xlo_fmt - QCOW file format
+ * @dest - destination buffer, @dest_size bytes
+ * @src - source buffer, @src_size bytes
+ *
+ * Returns: compressed size on success
+ * a negative error code on failure
+ */
+static ssize_t __qcow_file_fmt_buffer_decompress(struct xloop_file_fmt *xlo_fmt,
+ void *dest,
+ size_t dest_size,
+ const void *src,
+ size_t src_size)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ qcow_file_fmt_decompress_fn decompress_fn;
+
+ switch (qcow_data->compression_type) {
+ case QCOW_COMPRESSION_TYPE_ZLIB:
+ decompress_fn = __qcow_file_fmt_zlib_decompress;
+ break;
+
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ case QCOW_COMPRESSION_TYPE_ZSTD:
+ decompress_fn = __qcow_file_fmt_zstd_decompress;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return decompress_fn(xlo_fmt, dest, dest_size, src, src_size);
+}
+
+
+static int __qcow_file_fmt_read_compressed(struct xloop_file_fmt *xlo_fmt,
+ struct bio_vec *bvec,
+ u64 file_cluster_offset,
+ u64 offset,
+ u64 bytes,
+ u64 bytes_done)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ int ret = 0, csize, nb_csectors;
+ u64 coffset;
+ u8 *in_buf = NULL;
+ ssize_t len;
+ void *data;
+ unsigned long irq_flags;
+ int offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(
+ qcow_data, offset);
+
+ coffset = file_cluster_offset & qcow_data->cluster_offset_mask;
+ nb_csectors = ((file_cluster_offset >> qcow_data->csize_shift) &
+ qcow_data->csize_mask) + 1;
+ csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE -
+ (coffset & ~QCOW_COMPRESSED_SECTOR_MASK);
+
+
+ if (qcow_data->cmp_last_coffset != coffset) {
+ in_buf = vmalloc(csize);
+ if (!in_buf) {
+ qcow_data->cmp_last_coffset = ULLONG_MAX;
+ return -ENOMEM;
+ }
+ qcow_data->cmp_last_coffset = coffset;
+ len = kernel_read(xlo->xlo_backing_file, in_buf, csize, &coffset);
+ if (len < 0) {
+ qcow_data->cmp_last_coffset = ULLONG_MAX;
+ ret = len;
+ goto out_free_in_buf;
+ }
+
+ if (__qcow_file_fmt_buffer_decompress(xlo_fmt, qcow_data->cmp_out_buf,
+ qcow_data->cluster_size, in_buf, csize) < 0) {
+ qcow_data->cmp_last_coffset = ULLONG_MAX;
+ ret = -EIO;
+ goto out_free_in_buf;
+ }
+ }
+
+ ASSERT(bytes <= bvec->bv_len);
+ data = bvec_kmap_irq(bvec, &irq_flags) + bytes_done;
+ memcpy(data, qcow_data->cmp_out_buf + offset_in_cluster, bytes);
+ flush_dcache_page(bvec->bv_page);
+ bvec_kunmap_irq(data, &irq_flags);
+
+out_free_in_buf:
+ vfree(in_buf);
+
+ return ret;
+}
+
+static int __qcow_file_fmt_read_bvec(struct xloop_file_fmt *xlo_fmt,
+ struct bio_vec *bvec,
+ loff_t *ppos)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ int offset_in_cluster;
+ int ret;
+ unsigned int cur_bytes; /* number of bytes in current iteration */
+ u64 bytes;
+ u64 host_offset = 0;
+ u64 bytes_done = 0;
+ enum xloop_file_fmt_qcow_subcluster_type type;
+ void *data;
+ unsigned long irq_flags;
+ ssize_t len;
+ loff_t pos_read;
+
+ bytes = bvec->bv_len;
+
+ while (bytes != 0) {
+
+ /* prepare next request */
+ cur_bytes = bytes;
+
+ ret = xloop_file_fmt_qcow_get_host_offset(xlo_fmt, *ppos,
+ &cur_bytes, &host_offset, &type);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ offset_in_cluster = xloop_file_fmt_qcow_offset_into_cluster(
+ qcow_data, *ppos);
+
+ switch (type) {
+ case QCOW_SUBCLUSTER_ZERO_PLAIN:
+ case QCOW_SUBCLUSTER_ZERO_ALLOC:
+ case QCOW_SUBCLUSTER_UNALLOCATED_PLAIN:
+ case QCOW_SUBCLUSTER_UNALLOCATED_ALLOC:
+ data = bvec_kmap_irq(bvec, &irq_flags) + bytes_done;
+ memset(data, 0, cur_bytes);
+ flush_dcache_page(bvec->bv_page);
+ bvec_kunmap_irq(data, &irq_flags);
+ break;
+
+ case QCOW_SUBCLUSTER_COMPRESSED:
+ ret = __qcow_file_fmt_read_compressed(xlo_fmt, bvec,
+ host_offset, *ppos, cur_bytes, bytes_done);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ break;
+
+ case QCOW_SUBCLUSTER_NORMAL:
+ pos_read = host_offset;
+
+ data = bvec_kmap_irq(bvec, &irq_flags) + bytes_done;
+ len = kernel_read(xlo->xlo_backing_file, data, cur_bytes,
+ &pos_read);
+ flush_dcache_page(bvec->bv_page);
+ bvec_kunmap_irq(data, &irq_flags);
+
+ if (len < 0)
+ return len;
+
+ ASSERT(len == cur_bytes);
+ break;
+
+ default:
+ ret = -EIO;
+ goto fail;
+ }
+
+ bytes -= cur_bytes;
+ *ppos += cur_bytes;
+ bytes_done += cur_bytes;
+ }
+
+ ret = 0;
+
+fail:
+ return ret;
+}
+
+static int qcow_file_fmt_read(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct bio_vec bvec;
+ struct req_iterator iter;
+ loff_t pos;
+ int ret = 0;
+
+ pos = __qcow_file_fmt_rq_get_pos(xlo_fmt, rq);
+
+ rq_for_each_segment(bvec, rq, iter) {
+ ret = __qcow_file_fmt_read_bvec(xlo_fmt, &bvec, &pos);
+ if (ret)
+ return ret;
+
+ cond_resched();
+ }
+
+ return ret;
+}
+
+static loff_t qcow_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt,
+ struct file *file, loff_t offset, loff_t sizelimit)
+{
+ struct xloop_file_fmt_qcow_header header;
+ loff_t xloopsize;
+ int ret;
+
+ /* temporary read the QCOW file header of other QCOW image file */
+ ret = __qcow_file_fmt_header_read(xlo_fmt, file, &header);
+ if (ret)
+ return 0;
+
+ /* compute xloopsize in bytes */
+ xloopsize = header.size;
+ if (offset > 0)
+ xloopsize -= offset;
+ /* offset is beyond i_size, weird but possible */
+ if (xloopsize < 0)
+ return 0;
+
+ if (sizelimit > 0 && sizelimit < xloopsize)
+ xloopsize = sizelimit;
+ /*
+ * Unfortunately, if we want to do I/O on the device,
+ * the number of 512-byte sectors has to fit into a sector_t.
+ */
+ return xloopsize >> 9;
+}
+
+static struct xloop_file_fmt_ops qcow_file_fmt_ops = {
+ .init = qcow_file_fmt_init,
+ .exit = qcow_file_fmt_exit,
+ .read = qcow_file_fmt_read,
+ .write = NULL,
+ .read_aio = NULL,
+ .write_aio = NULL,
+ .write_zeros = NULL,
+ .discard = NULL,
+ .flush = NULL,
+ .sector_size = qcow_file_fmt_sector_size,
+};
+
+static struct xloop_file_fmt_driver qcow_file_fmt_driver = {
+ .name = "QCOW",
+ .file_fmt_type = XLO_FILE_FMT_QCOW,
+ .ops = &qcow_file_fmt_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __init xloop_file_fmt_qcow_init(void)
+{
+ pr_info("init xloop device QCOW file format driver\n");
+ return xloop_file_fmt_register_driver(&qcow_file_fmt_driver);
+}
+
+static void __exit xloop_file_fmt_qcow_exit(void)
+{
+ pr_info("exit xloop device QCOW file format driver\n");
+ xloop_file_fmt_unregister_driver(&qcow_file_fmt_driver);
+}
+
+module_init(xloop_file_fmt_qcow_init);
+module_exit(xloop_file_fmt_qcow_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manuel Bentele <development@manuel-bentele.de>");
+MODULE_DESCRIPTION("xloop device QCOW file format driver");
+MODULE_SOFTDEP("pre: xloop");
+MODULE_VERSION(__stringify(VERSION));
diff --git a/src/kernel/xloop_file_fmt_qcow_main.h b/src/kernel/xloop_file_fmt_qcow_main.h
new file mode 100644
index 0000000..023c679
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_qcow_main.h
@@ -0,0 +1,646 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_qcow.h
+ *
+ * QCOW file format driver for the xloop device module.
+ *
+ * Ported QCOW2 implementation of the QEMU project (GPL-2.0):
+ * Declarations for the QCOW2 file format.
+ *
+ * The copyright (C) 2004-2006 of the original code is owned by Fabrice Bellard.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#ifndef _LINUX_XLOOP_FILE_FMT_QCOW_H
+#define _LINUX_XLOOP_FILE_FMT_QCOW_H
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/zlib.h>
+#ifdef CONFIG_ZSTD_DECOMPRESS
+#include <linux/zstd.h>
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#include "xloop_file_fmt.h"
+
+#ifdef CONFIG_DEBUG_DRIVER
+#define ASSERT(x) \
+do { \
+ if (!(x)) { \
+ printk(KERN_EMERG "assertion failed %s: %d: %s\n", \
+ __FILE__, __LINE__, #x); \
+ BUG(); \
+ } \
+} while (0)
+#else
+#define ASSERT(x) do { } while (0)
+#endif
+
+#define KiB (1024)
+#define MiB (1024 * 1024)
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES 1
+#define QCOW_CRYPT_LUKS 2
+
+#define QCOW_MAX_CRYPT_CLUSTERS 32
+#define QCOW_MAX_SNAPSHOTS 65536
+
+/* Field widths in QCOW mean normal cluster offsets cannot reach
+ * 64PB; depending on cluster size, compressed clusters can have a
+ * smaller limit (64PB for up to 16k clusters, then ramps down to
+ * 512TB for 2M clusters). */
+#define QCOW_MAX_CLUSTER_OFFSET ((1ULL << 56) - 1)
+
+/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
+#define QCOW_MAX_REFTABLE_SIZE (8 * MiB)
+
+/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
+ * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
+#define QCOW_MAX_L1_SIZE (32 * MiB)
+
+/* Allow for an average of 1k per snapshot table entry, should be plenty of
+ * space for snapshot names and IDs */
+#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
+
+/* Bitmap header extension constraints */
+#define QCOW_MAX_BITMAPS 65535
+#define QCOW_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW_MAX_BITMAPS)
+
+/* indicate that the refcount of the referenced cluster is exactly one. */
+#define QCOW_OFLAG_COPIED (1ULL << 63)
+/* indicate that the cluster is compressed (they never have the copied flag) */
+#define QCOW_OFLAG_COMPRESSED (1ULL << 62)
+/* The cluster reads as all zeros */
+#define QCOW_OFLAG_ZERO (1ULL << 0)
+
+#define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32
+
+/* The subcluster X [0..31] is allocated */
+#define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X))
+/* The subcluster X [0..31] reads as zeroes */
+#define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32)
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) are allocated */
+#define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) \
+ (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X))
+/* Subclusters [X, Y) (0 <= X <= Y <= 32) read as zeroes */
+#define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) \
+ (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32)
+/* L2 entry bitmap with all allocation bits set */
+#define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32))
+/* L2 entry bitmap with all "read as zeroes" bits set */
+#define QCOW_L2_BITMAP_ALL_ZEROES (QCOW_OFLAG_SUB_ZERO_RANGE(0, 32))
+
+/* Size of normal and extended L2 entries */
+#define QCOW_L2E_SIZE_NORMAL (sizeof(u64))
+#define QCOW_L2E_SIZE_EXTENDED (sizeof(u64) * 2)
+
+/* Size of L1 table entries */
+#define QCOW_L1E_SIZE (sizeof(u64))
+
+/* Size of reftable entries */
+#define QCOW_REFTABLE_ENTRY_SIZE (sizeof(u64))
+
+#define QCOW_MIN_CLUSTER_BITS 9
+#define QCOW_MAX_CLUSTER_BITS 21
+
+/* Defined in the qcow2 spec (compressed cluster descriptor) */
+#define QCOW_COMPRESSED_SECTOR_SIZE 512U
+#define QCOW_COMPRESSED_SECTOR_MASK (~(QCOW_COMPRESSED_SECTOR_SIZE - 1))
+
+/* Must be at least 2 to cover COW */
+#define QCOW_MIN_L2_CACHE_SIZE 2 /* cache entries */
+
+/* Must be at least 4 to cover all cases of refcount table growth */
+#define QCOW_MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */
+
+#define QCOW_DEFAULT_L2_CACHE_MAX_SIZE (32 * MiB)
+#define QCOW_DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */
+
+#define QCOW_DEFAULT_CLUSTER_SIZE 65536
+
+/* Buffer size for debugfs file buffer to display QCOW header information */
+#define QCOW_HEADER_BUF_LEN 1024
+
+/* Buffer size for debugfs file buffer to receive and display offset and
+ * cluster offset information */
+#define QCOW_OFFSET_BUF_LEN 32
+#define QCOW_CLUSTER_BUF_LEN 256
+
+struct xloop_file_fmt_qcow_header {
+ u32 magic;
+ u32 version;
+ u64 backing_file_offset;
+ u32 backing_file_size;
+ u32 cluster_bits;
+ u64 size; /* in bytes */
+ u32 crypt_method;
+ u32 l1_size;
+ u64 l1_table_offset;
+ u64 refcount_table_offset;
+ u32 refcount_table_clusters;
+ u32 nb_snapshots;
+ u64 snapshots_offset;
+
+ /* The following fields are only valid for version >= 3 */
+ u64 incompatible_features;
+ u64 compatible_features;
+ u64 autoclear_features;
+
+ u32 refcount_order;
+ u32 header_length;
+
+ /* Additional fields */
+ u8 compression_type;
+
+ /* header must be a multiple of 8 */
+ u8 padding[7];
+} __attribute__((packed));
+
+struct xloop_file_fmt_qcow_snapshot_header {
+ /* header is 8 byte aligned */
+ u64 l1_table_offset;
+
+ u32 l1_size;
+ u16 id_str_size;
+ u16 name_size;
+
+ u32 date_sec;
+ u32 date_nsec;
+
+ u64 vm_clock_nsec;
+
+ u32 vm_state_size;
+
+ /* Size of all extra data, including QCowSnapshotExtraData if available */
+ u32 extra_data_size;
+ /* Data beyond QCowSnapshotExtraData, if any */
+ void *unknown_extra_data;
+} __attribute__((packed));
+
+enum {
+ QCOW_FEAT_TYPE_INCOMPATIBLE = 0,
+ QCOW_FEAT_TYPE_COMPATIBLE = 1,
+ QCOW_FEAT_TYPE_AUTOCLEAR = 2,
+};
+
+/* incompatible feature bits */
+enum {
+ QCOW_INCOMPAT_DIRTY_BITNR = 0,
+ QCOW_INCOMPAT_CORRUPT_BITNR = 1,
+ QCOW_INCOMPAT_DATA_FILE_BITNR = 2,
+ QCOW_INCOMPAT_COMPRESSION_BITNR = 3,
+ QCOW_INCOMPAT_EXTL2_BITNR = 4,
+ QCOW_INCOMPAT_DIRTY = 1 << QCOW_INCOMPAT_DIRTY_BITNR,
+ QCOW_INCOMPAT_CORRUPT = 1 << QCOW_INCOMPAT_CORRUPT_BITNR,
+ QCOW_INCOMPAT_DATA_FILE = 1 << QCOW_INCOMPAT_DATA_FILE_BITNR,
+ QCOW_INCOMPAT_COMPRESSION = 1 << QCOW_INCOMPAT_COMPRESSION_BITNR,
+ QCOW_INCOMPAT_EXTL2 = 1 << QCOW_INCOMPAT_EXTL2_BITNR,
+
+ QCOW_INCOMPAT_MASK = QCOW_INCOMPAT_DIRTY
+ | QCOW_INCOMPAT_CORRUPT
+ | QCOW_INCOMPAT_DATA_FILE
+ | QCOW_INCOMPAT_COMPRESSION
+ | QCOW_INCOMPAT_EXTL2,
+};
+
+/* compatible feature bits */
+enum {
+ QCOW_COMPAT_LAZY_REFCOUNTS_BITNR = 0,
+ QCOW_COMPAT_LAZY_REFCOUNTS = 1 << QCOW_COMPAT_LAZY_REFCOUNTS_BITNR,
+
+ QCOW_COMPAT_FEAT_MASK = QCOW_COMPAT_LAZY_REFCOUNTS,
+};
+
+/* autoclear feature bits */
+enum {
+ QCOW_AUTOCLEAR_BITMAPS_BITNR = 0,
+ QCOW_AUTOCLEAR_DATA_FILE_RAW_BITNR = 1,
+ QCOW_AUTOCLEAR_BITMAPS = 1 << QCOW_AUTOCLEAR_BITMAPS_BITNR,
+ QCOW_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW_AUTOCLEAR_DATA_FILE_RAW_BITNR,
+
+ QCOW_AUTOCLEAR_MASK = QCOW_AUTOCLEAR_BITMAPS |
+ QCOW_AUTOCLEAR_DATA_FILE_RAW,
+};
+
+enum xloop_file_fmt_qcow_compression_type {
+ QCOW_COMPRESSION_TYPE_ZLIB,
+ QCOW_COMPRESSION_TYPE_ZSTD,
+};
+
+struct xloop_file_fmt_qcow_data {
+ u64 size;
+ int cluster_bits;
+ int cluster_size;
+ int l2_slice_size;
+ int subcluster_bits;
+ int subcluster_size;
+ int subclusters_per_cluster;
+ int l2_bits;
+ int l2_size;
+ int l1_size;
+ int l1_vm_state_index;
+ int refcount_block_bits;
+ int refcount_block_size;
+ int csize_shift;
+ int csize_mask;
+ u64 cluster_offset_mask;
+ u64 l1_table_offset;
+ u64 *l1_table;
+
+ struct xloop_file_fmt_qcow_cache *l2_table_cache;
+ struct xloop_file_fmt_qcow_cache *refcount_block_cache;
+
+ u64 *refcount_table;
+ u64 refcount_table_offset;
+ u32 refcount_table_size;
+ u32 max_refcount_table_index; /* Last used entry in refcount_table */
+ u64 free_cluster_index;
+ u64 free_byte_offset;
+
+ u32 crypt_method_header;
+ u64 snapshots_offset;
+ int snapshots_size;
+ unsigned int nb_snapshots;
+
+ u32 nb_bitmaps;
+ u64 bitmap_directory_size;
+ u64 bitmap_directory_offset;
+
+ int qcow_version;
+ bool use_lazy_refcounts;
+ int refcount_order;
+ int refcount_bits;
+ u64 refcount_max;
+
+ u64 incompatible_features;
+ u64 compatible_features;
+ u64 autoclear_features;
+
+ /* ZLIB specific data */
+ z_streamp zlib_dstrm;
+
+ /* ZSTD specific data */
+#ifdef CONFIG_ZSTD_DECOMPRESS
+ void *zstd_dworkspace;
+ ZSTD_DStream *zstd_dstrm;
+#endif
+
+ /* used to cache last compressed QCOW cluster */
+ u8 *cmp_out_buf;
+ u64 cmp_last_coffset;
+
+ /*
+ * Compression type used for the image. Default: 0 - ZLIB
+ * The image compression type is set on image creation.
+ * For now, the only way to change the compression type
+ * is to convert the image with the desired compression type set.
+ */
+ enum xloop_file_fmt_qcow_compression_type compression_type;
+
+ /* debugfs entries */
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_file_qcow_header;
+ char dbgfs_file_qcow_header_buf[QCOW_HEADER_BUF_LEN];
+ struct dentry *dbgfs_file_qcow_offset;
+ char dbgfs_file_qcow_offset_buf[QCOW_OFFSET_BUF_LEN];
+ char dbgfs_file_qcow_cluster_buf[QCOW_CLUSTER_BUF_LEN];
+ u64 dbgfs_qcow_offset;
+ struct mutex dbgfs_qcow_offset_mutex;
+#endif
+};
+
+struct xloop_file_fmt_qcow_cow_region {
+ /**
+ * Offset of the COW region in bytes from the start of the first
+ * cluster touched by the request.
+ */
+ unsigned offset;
+
+ /** Number of bytes to copy */
+ unsigned nb_bytes;
+};
+
+/*
+ * In images with standard L2 entries all clusters are treated as if
+ * they had one subcluster so xloop_file_fmt_qcow_cluster_type and
+ * xloop_file_fmt_qcow_subcluster_type can be mapped to each other and
+ * have the exact same meaning (QCOW_SUBCLUSTER_UNALLOCATED_ALLOC cannot
+ * happen in these images).
+ *
+ * In images with extended L2 entries xloop_file_fmt_qcow_cluster_type
+ * refers to the complete cluster and xloop_file_fmt_qcow_subcluster_type
+ * to each of the individual subclusters, so there are several possible
+ * combinations:
+ *
+ * |--------------+---------------------------|
+ * | Cluster type | Possible subcluster types |
+ * |--------------+---------------------------|
+ * | UNALLOCATED | UNALLOCATED_PLAIN |
+ * | | ZERO_PLAIN |
+ * |--------------+---------------------------|
+ * | NORMAL | UNALLOCATED_ALLOC |
+ * | | ZERO_ALLOC |
+ * | | NORMAL |
+ * |--------------+---------------------------|
+ * | COMPRESSED | COMPRESSED |
+ * |--------------+---------------------------|
+ *
+ * QCOW_SUBCLUSTER_INVALID means that the L2 entry is incorrect and
+ * the image should be marked corrupt.
+ */
+enum xloop_file_fmt_qcow_cluster_type {
+ QCOW_CLUSTER_UNALLOCATED,
+ QCOW_CLUSTER_ZERO_PLAIN,
+ QCOW_CLUSTER_ZERO_ALLOC,
+ QCOW_CLUSTER_NORMAL,
+ QCOW_CLUSTER_COMPRESSED,
+};
+
+enum xloop_file_fmt_qcow_subcluster_type {
+ QCOW_SUBCLUSTER_UNALLOCATED_PLAIN,
+ QCOW_SUBCLUSTER_UNALLOCATED_ALLOC,
+ QCOW_SUBCLUSTER_ZERO_PLAIN,
+ QCOW_SUBCLUSTER_ZERO_ALLOC,
+ QCOW_SUBCLUSTER_NORMAL,
+ QCOW_SUBCLUSTER_COMPRESSED,
+ QCOW_SUBCLUSTER_INVALID,
+};
+
+enum xloop_file_fmt_qcow_metadata_overlap {
+ QCOW_OL_MAIN_HEADER_BITNR = 0,
+ QCOW_OL_ACTIVE_L1_BITNR = 1,
+ QCOW_OL_ACTIVE_L2_BITNR = 2,
+ QCOW_OL_REFCOUNT_TABLE_BITNR = 3,
+ QCOW_OL_REFCOUNT_BLOCK_BITNR = 4,
+ QCOW_OL_SNAPSHOT_TABLE_BITNR = 5,
+ QCOW_OL_INACTIVE_L1_BITNR = 6,
+ QCOW_OL_INACTIVE_L2_BITNR = 7,
+ QCOW_OL_BITMAP_DIRECTORY_BITNR = 8,
+
+ QCOW_OL_MAX_BITNR = 9,
+
+ QCOW_OL_NONE = 0,
+ QCOW_OL_MAIN_HEADER = (1 << QCOW_OL_MAIN_HEADER_BITNR),
+ QCOW_OL_ACTIVE_L1 = (1 << QCOW_OL_ACTIVE_L1_BITNR),
+ QCOW_OL_ACTIVE_L2 = (1 << QCOW_OL_ACTIVE_L2_BITNR),
+ QCOW_OL_REFCOUNT_TABLE = (1 << QCOW_OL_REFCOUNT_TABLE_BITNR),
+ QCOW_OL_REFCOUNT_BLOCK = (1 << QCOW_OL_REFCOUNT_BLOCK_BITNR),
+ QCOW_OL_SNAPSHOT_TABLE = (1 << QCOW_OL_SNAPSHOT_TABLE_BITNR),
+ QCOW_OL_INACTIVE_L1 = (1 << QCOW_OL_INACTIVE_L1_BITNR),
+ /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv
+ * reads. */
+ QCOW_OL_INACTIVE_L2 = (1 << QCOW_OL_INACTIVE_L2_BITNR),
+ QCOW_OL_BITMAP_DIRECTORY = (1 << QCOW_OL_BITMAP_DIRECTORY_BITNR),
+};
+
+/* Perform all overlap checks which can be done in constant time */
+#define QCOW_OL_CONSTANT \
+ (QCOW_OL_MAIN_HEADER | QCOW_OL_ACTIVE_L1 | QCOW_OL_REFCOUNT_TABLE | \
+ QCOW_OL_SNAPSHOT_TABLE | QCOW_OL_BITMAP_DIRECTORY)
+
+/* Perform all overlap checks which don't require disk access */
+#define QCOW_OL_CACHED \
+ (QCOW_OL_CONSTANT | QCOW_OL_ACTIVE_L2 | QCOW_OL_REFCOUNT_BLOCK | \
+ QCOW_OL_INACTIVE_L1)
+
+/* Perform all overlap checks */
+#define QCOW_OL_ALL \
+ (QCOW_OL_CACHED | QCOW_OL_INACTIVE_L2)
+
+#define QCOW_L1E_OFFSET_MASK 0x00fffffffffffe00ULL
+#define QCOW_L2E_OFFSET_MASK 0x00fffffffffffe00ULL
+#define QCOW_L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+
+static inline bool xloop_file_fmt_qcow_has_subclusters(
+ struct xloop_file_fmt_qcow_data *qcow_data)
+{
+ return qcow_data->incompatible_features & QCOW_INCOMPAT_EXTL2;
+}
+
+static inline size_t xloop_file_fmt_qcow_l2_entry_size(
+ struct xloop_file_fmt_qcow_data *qcow_data)
+{
+ return xloop_file_fmt_qcow_has_subclusters(qcow_data) ?
+ QCOW_L2E_SIZE_EXTENDED : QCOW_L2E_SIZE_NORMAL;
+}
+
+static inline u64 xloop_file_fmt_qcow_get_l2_entry(
+ struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx)
+{
+ idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64);
+ return be64_to_cpu(l2_slice[idx]);
+}
+
+static inline u64 xloop_file_fmt_qcow_get_l2_bitmap(
+ struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx)
+{
+ if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) {
+ idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64);
+ return be64_to_cpu(l2_slice[idx + 1]);
+ } else {
+ return 0; /* For convenience only; this value has no meaning. */
+ }
+}
+
+static inline bool xloop_file_fmt_qcow_has_data_file(
+ struct xloop_file_fmt_qcow_data *qcow_data)
+{
+ /* At the moment, there is no support for copy on write! */
+ return false;
+}
+
+static inline bool xloop_file_fmt_qcow_data_file_is_raw(
+ struct xloop_file_fmt_qcow_data *qcow_data)
+{
+ return !!(qcow_data->autoclear_features &
+ QCOW_AUTOCLEAR_DATA_FILE_RAW);
+}
+
+static inline s64 xloop_file_fmt_qcow_start_of_cluster(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return offset & ~(qcow_data->cluster_size - 1);
+}
+
+static inline s64 xloop_file_fmt_qcow_offset_into_cluster(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return offset & (qcow_data->cluster_size - 1);
+}
+
+static inline s64 xloop_file_fmt_qcow_offset_into_subcluster(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return offset & (qcow_data->subcluster_size - 1);
+}
+
+static inline s64 xloop_file_fmt_qcow_size_to_clusters(
+ struct xloop_file_fmt_qcow_data *qcow_data, u64 size)
+{
+ return (size + (qcow_data->cluster_size - 1)) >>
+ qcow_data->cluster_bits;
+}
+
+static inline s64 xloop_file_fmt_qcow_size_to_l1(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 size)
+{
+ int shift = qcow_data->cluster_bits + qcow_data->l2_bits;
+ return (size + (1ULL << shift) - 1) >> shift;
+}
+
+static inline int xloop_file_fmt_qcow_offset_to_l1_index(
+ struct xloop_file_fmt_qcow_data *qcow_data, u64 offset)
+{
+ return offset >> (qcow_data->l2_bits + qcow_data->cluster_bits);
+}
+
+static inline int xloop_file_fmt_qcow_offset_to_l2_index(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return (offset >> qcow_data->cluster_bits) & (qcow_data->l2_size - 1);
+}
+
+static inline int xloop_file_fmt_qcow_offset_to_l2_slice_index(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return (offset >> qcow_data->cluster_bits) &
+ (qcow_data->l2_slice_size - 1);
+}
+
+static inline int xloop_file_fmt_qcow_offset_to_sc_index(
+ struct xloop_file_fmt_qcow_data *qcow_data, s64 offset)
+{
+ return (offset >> qcow_data->subcluster_bits) &
+ (qcow_data->subclusters_per_cluster - 1);
+}
+
+static inline s64 xloop_file_fmt_qcow_vm_state_offset(
+ struct xloop_file_fmt_qcow_data *qcow_data)
+{
+ return (s64)qcow_data->l1_vm_state_index <<
+ (qcow_data->cluster_bits + qcow_data->l2_bits);
+}
+
+static inline enum xloop_file_fmt_qcow_cluster_type
+xloop_file_fmt_qcow_get_cluster_type(struct xloop_file_fmt *xlo_fmt,
+ u64 l2_entry)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+
+ if (l2_entry & QCOW_OFLAG_COMPRESSED) {
+ return QCOW_CLUSTER_COMPRESSED;
+ } else if (l2_entry & QCOW_OFLAG_ZERO) {
+ if (l2_entry & QCOW_L2E_OFFSET_MASK) {
+ return QCOW_CLUSTER_ZERO_ALLOC;
+ }
+ return QCOW_CLUSTER_ZERO_PLAIN;
+ } else if (!(l2_entry & QCOW_L2E_OFFSET_MASK)) {
+ /* Offset 0 generally means unallocated, but it is ambiguous
+ * with external data files because 0 is a valid offset there.
+ * However, all clusters in external data files always have
+ * refcount 1, so we can rely on QCOW_OFLAG_COPIED to
+ * disambiguate. */
+ if (xloop_file_fmt_qcow_has_data_file(qcow_data) &&
+ (l2_entry & QCOW_OFLAG_COPIED)) {
+ return QCOW_CLUSTER_NORMAL;
+ } else {
+ return QCOW_CLUSTER_UNALLOCATED;
+ }
+ } else {
+ return QCOW_CLUSTER_NORMAL;
+ }
+}
+
+/*
+ * In an image without subsclusters @l2_bitmap is ignored and
+ * @sc_index must be 0.
+ * Return QCOW_SUBCLUSTER_INVALID if an invalid l2 entry is detected
+ * (this checks the whole entry and bitmap, not only the bits related
+ * to subcluster @sc_index).
+ */
+static inline enum xloop_file_fmt_qcow_subcluster_type
+xloop_file_fmt_qcow_get_subcluster_type(struct xloop_file_fmt *xlo_fmt,
+ u64 l2_entry, u64 l2_bitmap, unsigned int sc_index)
+{
+ struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data;
+ enum xloop_file_fmt_qcow_cluster_type type =
+ xloop_file_fmt_qcow_get_cluster_type(xlo_fmt, l2_entry);
+ ASSERT(sc_index < qcow_data->subclusters_per_cluster);
+
+ if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) {
+ switch (type) {
+ case QCOW_CLUSTER_COMPRESSED:
+ return QCOW_SUBCLUSTER_COMPRESSED;
+ case QCOW_CLUSTER_NORMAL:
+ if ((l2_bitmap >> 32) & l2_bitmap) {
+ return QCOW_SUBCLUSTER_INVALID;
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) {
+ return QCOW_SUBCLUSTER_ZERO_ALLOC;
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ALLOC(sc_index)) {
+ return QCOW_SUBCLUSTER_NORMAL;
+ } else {
+ return QCOW_SUBCLUSTER_UNALLOCATED_ALLOC;
+ }
+ case QCOW_CLUSTER_UNALLOCATED:
+ if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) {
+ return QCOW_SUBCLUSTER_INVALID;
+ } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) {
+ return QCOW_SUBCLUSTER_ZERO_PLAIN;
+ } else {
+ return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN;
+ }
+ default:
+ /* not reachable */
+ ASSERT(false);
+ return QCOW_SUBCLUSTER_INVALID;
+ }
+ } else {
+ switch (type) {
+ case QCOW_CLUSTER_COMPRESSED:
+ return QCOW_SUBCLUSTER_COMPRESSED;
+ case QCOW_CLUSTER_ZERO_PLAIN:
+ return QCOW_SUBCLUSTER_ZERO_PLAIN;
+ case QCOW_CLUSTER_ZERO_ALLOC:
+ return QCOW_SUBCLUSTER_ZERO_ALLOC;
+ case QCOW_CLUSTER_NORMAL:
+ return QCOW_SUBCLUSTER_NORMAL;
+ case QCOW_CLUSTER_UNALLOCATED:
+ return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN;
+ default:
+ /* not reachable */
+ ASSERT(false);
+ return QCOW_SUBCLUSTER_INVALID;
+ }
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static inline const char *xloop_file_fmt_qcow_get_subcluster_name(
+ const enum xloop_file_fmt_qcow_subcluster_type type)
+{
+ static const char *subcluster_names[] = {
+ "QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN",
+ "QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC",
+ "QCOW2_SUBCLUSTER_ZERO_PLAIN",
+ "QCOW2_SUBCLUSTER_ZERO_ALLOC",
+ "QCOW2_SUBCLUSTER_NORMAL",
+ "QCOW2_SUBCLUSTER_COMPRESSED",
+ "QCOW2_SUBCLUSTER_INVALID"
+ };
+
+ return subcluster_names[type];
+}
+#endif
+
+#endif
diff --git a/src/kernel/xloop_file_fmt_raw.c b/src/kernel/xloop_file_fmt_raw.c
new file mode 100644
index 0000000..76ab39e
--- /dev/null
+++ b/src/kernel/xloop_file_fmt_raw.c
@@ -0,0 +1,476 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xloop_file_fmt_raw.c
+ *
+ * RAW file format driver for the xloop device module.
+ *
+ * Copyright (C) 2019 Manuel Bentele <development@manuel-bentele.de>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/compiler.h>
+#include <linux/blk-cgroup.h>
+#include <linux/fs.h>
+#include <linux/falloc.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/version.h>
+
+#include "xloop_file_fmt.h"
+
+static inline loff_t __raw_file_fmt_rq_get_pos(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ return ((loff_t) blk_rq_pos(rq) << 9) + xlo->xlo_offset;
+}
+
+/* transfer function for DEPRECATED cryptoxloop support */
+static inline int __raw_file_fmt_do_transfer(struct xloop_device *xlo, int cmd,
+ struct page *rpage, unsigned roffs,
+ struct page *lpage, unsigned loffs,
+ int size, sector_t rblock)
+{
+ int ret;
+
+ ret = xlo->transfer(xlo, cmd, rpage, roffs, lpage, loffs, size, rblock);
+ if (likely(!ret))
+ return 0;
+
+ pr_err_ratelimited("transfer error at byte offset %llu, length %i.\n",
+ (unsigned long long)rblock << 9, size);
+ return ret;
+}
+
+static int __raw_file_fmt_read_transfer(struct xloop_device *xlo,
+ struct request *rq, loff_t pos)
+{
+ struct bio_vec bvec, b;
+ struct req_iterator iter;
+ struct iov_iter i;
+ struct page *page;
+ ssize_t len;
+ int ret = 0;
+
+ page = alloc_page(GFP_NOIO);
+ if (unlikely(!page))
+ return -ENOMEM;
+
+ rq_for_each_segment(bvec, rq, iter) {
+ loff_t offset = pos;
+
+ b.bv_page = page;
+ b.bv_offset = 0;
+ b.bv_len = bvec.bv_len;
+
+ iov_iter_bvec(&i, READ, &b, 1, b.bv_len);
+ len = vfs_iter_read(xlo->xlo_backing_file, &i, &pos, 0);
+ if (len < 0) {
+ ret = len;
+ goto out_free_page;
+ }
+
+ ret = __raw_file_fmt_do_transfer(xlo, READ, page, 0, bvec.bv_page,
+ bvec.bv_offset, len, offset >> 9);
+ if (ret)
+ goto out_free_page;
+
+ flush_dcache_page(bvec.bv_page);
+
+ if (len != bvec.bv_len) {
+ struct bio *bio;
+
+ __rq_for_each_bio(bio, rq)
+ zero_fill_bio(bio);
+ break;
+ }
+ }
+
+ ret = 0;
+out_free_page:
+ __free_page(page);
+ return ret;
+}
+
+static int raw_file_fmt_read(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct bio_vec bvec;
+ struct req_iterator iter;
+ struct iov_iter i;
+ ssize_t len;
+ struct xloop_device *xlo;
+ loff_t pos;
+
+ xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+
+ if (xlo->transfer)
+ return __raw_file_fmt_read_transfer(xlo, rq, pos);
+
+ rq_for_each_segment(bvec, rq, iter) {
+ iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len);
+ len = vfs_iter_read(xlo->xlo_backing_file, &i, &pos, 0);
+ if (len < 0)
+ return len;
+
+ flush_dcache_page(bvec.bv_page);
+
+ if (len != bvec.bv_len) {
+ struct bio *bio;
+
+ __rq_for_each_bio(bio, rq)
+ zero_fill_bio(bio);
+ break;
+ }
+ cond_resched();
+ }
+
+ return 0;
+}
+
+static void __raw_file_fmt_rw_aio_do_completion(struct xloop_cmd *cmd)
+{
+ struct request *rq = blk_mq_rq_from_pdu(cmd);
+
+ if (!atomic_dec_and_test(&cmd->ref))
+ return;
+ kfree(cmd->bvec);
+ cmd->bvec = NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+ if (likely(!blk_should_fake_timeout(rq->q)))
+ blk_mq_complete_request(rq);
+#else
+ blk_mq_complete_request(rq);
+#endif
+}
+
+static void __raw_file_fmt_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
+{
+ struct xloop_cmd *cmd = container_of(iocb, struct xloop_cmd, iocb);
+
+ if (cmd->css)
+ css_put(cmd->css);
+ cmd->ret = ret;
+ __raw_file_fmt_rw_aio_do_completion(cmd);
+}
+
+static int __raw_file_fmt_rw_aio(struct xloop_device *xlo,
+ struct xloop_cmd *cmd, loff_t pos, bool rw)
+{
+ struct iov_iter iter;
+ struct req_iterator rq_iter;
+ struct bio_vec *bvec;
+ struct request *rq = blk_mq_rq_from_pdu(cmd);
+ struct bio *bio = rq->bio;
+ struct file *file = xlo->xlo_backing_file;
+ struct bio_vec tmp;
+ unsigned int offset;
+ int nr_bvec = 0;
+ int ret;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+ rq_for_each_bvec(tmp, rq, rq_iter)
+ nr_bvec++;
+#endif
+
+ if (rq->bio != rq->biotail) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
+ __rq_for_each_bio(bio, rq)
+ nr_bvec += bio_segments(bio);
+#endif
+ bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
+ GFP_NOIO);
+ if (!bvec)
+ return -EIO;
+ cmd->bvec = bvec;
+
+ /*
+ * The bios of the request may be started from the middle of
+ * the 'bvec' because of bio splitting, so we can't directly
+ * copy bio->bi_iov_vec to new bvec. The rq_for_each_bvec
+ * API will take care of all details for us.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
+ rq_for_each_bvec(tmp, rq, rq_iter) {
+#else
+ rq_for_each_segment(tmp, rq, rq_iter) {
+#endif
+ *bvec = tmp;
+ bvec++;
+ }
+ bvec = cmd->bvec;
+ offset = 0;
+ } else {
+ /*
+ * Same here, this bio may be started from the middle of the
+ * 'bvec' because of bio splitting, so offset from the bvec
+ * must be passed to iov iterator
+ */
+ offset = bio->bi_iter.bi_bvec_done;
+ bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
+ nr_bvec = bio_segments(bio);
+#endif
+ }
+ atomic_set(&cmd->ref, 2);
+
+ iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq));
+ iter.iov_offset = offset;
+
+ cmd->iocb.ki_pos = pos;
+ cmd->iocb.ki_filp = file;
+ cmd->iocb.ki_complete = __raw_file_fmt_rw_aio_complete;
+ cmd->iocb.ki_flags = IOCB_DIRECT;
+ cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0);
+ if (cmd->css)
+ kthread_associate_blkcg(cmd->css);
+
+ if (rw == WRITE)
+ ret = call_write_iter(file, &cmd->iocb, &iter);
+ else
+ ret = call_read_iter(file, &cmd->iocb, &iter);
+
+ __raw_file_fmt_rw_aio_do_completion(cmd);
+ kthread_associate_blkcg(NULL);
+
+ if (ret != -EIOCBQUEUED)
+ cmd->iocb.ki_complete(&cmd->iocb, ret, 0);
+ return 0;
+}
+
+static int raw_file_fmt_read_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+
+ return __raw_file_fmt_rw_aio(xlo, cmd, pos, READ);
+}
+
+static int __raw_file_fmt_write_bvec(struct file *file,
+ struct bio_vec *bvec,
+ loff_t *ppos)
+{
+ struct iov_iter i;
+ ssize_t bw;
+
+ iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len);
+
+ file_start_write(file);
+ bw = vfs_iter_write(file, &i, ppos, 0);
+ file_end_write(file);
+
+ if (likely(bw == bvec->bv_len))
+ return 0;
+
+ pr_err_ratelimited("write error at byte offset %llu, length %i.\n",
+ (unsigned long long)*ppos, bvec->bv_len);
+ if (bw >= 0)
+ bw = -EIO;
+ return bw;
+}
+
+/*
+ * This is the slow, transforming version that needs to double buffer the
+ * data as it cannot do the transformations in place without having direct
+ * access to the destination pages of the backing file.
+ */
+static int __raw_file_fmt_write_transfer(struct xloop_device *xlo,
+ struct request *rq, loff_t pos)
+{
+struct bio_vec bvec, b;
+ struct req_iterator iter;
+ struct page *page;
+ int ret = 0;
+
+ page = alloc_page(GFP_NOIO);
+ if (unlikely(!page))
+ return -ENOMEM;
+
+ rq_for_each_segment(bvec, rq, iter) {
+ ret = __raw_file_fmt_do_transfer(xlo, WRITE, page, 0, bvec.bv_page,
+ bvec.bv_offset, bvec.bv_len, pos >> 9);
+ if (unlikely(ret))
+ break;
+
+ b.bv_page = page;
+ b.bv_offset = 0;
+ b.bv_len = bvec.bv_len;
+ ret = __raw_file_fmt_write_bvec(xlo->xlo_backing_file, &b, &pos);
+ if (ret < 0)
+ break;
+ }
+
+ __free_page(page);
+ return ret;
+}
+
+static int raw_file_fmt_write(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct bio_vec bvec;
+ struct req_iterator iter;
+ int ret = 0;
+ struct xloop_device *xlo;
+ loff_t pos;
+
+ xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+
+ if (xlo->transfer)
+ return __raw_file_fmt_write_transfer(xlo, rq, pos);
+
+ rq_for_each_segment(bvec, rq, iter) {
+ ret = __raw_file_fmt_write_bvec(xlo->xlo_backing_file, &bvec, &pos);
+ if (ret < 0)
+ break;
+ cond_resched();
+ }
+
+ return ret;
+}
+
+static int raw_file_fmt_write_aio(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+
+ return __raw_file_fmt_rw_aio(xlo, cmd, pos, WRITE);
+}
+
+static int __raw_file_fmt_fallocate(struct xloop_device *xlo,
+ struct request *rq, loff_t pos, int mode)
+{
+ /*
+ * We use fallocate to manipulate the space mappings used by the image
+ * a.k.a. discard/zerorange. However we do not support this if
+ * encryption is enabled, because it may give an attacker useful
+ * information.
+ */
+ struct file *file = xlo->xlo_backing_file;
+ struct request_queue *q = xlo->xlo_queue;
+ int ret;
+
+ mode |= FALLOC_FL_KEEP_SIZE;
+
+ if (!blk_queue_discard(q)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ ret = file->f_op->fallocate(file, mode, pos, blk_rq_bytes(rq));
+ if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP))
+ ret = -EIO;
+out:
+ return ret;
+}
+
+static int raw_file_fmt_write_zeros(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+
+ /*
+ * If the caller doesn't want deallocation, call zeroout to
+ * write zeroes the range. Otherwise, punch them out.
+ */
+ return __raw_file_fmt_fallocate(xlo, rq, pos,
+ (rq->cmd_flags & REQ_NOUNMAP) ?
+ FALLOC_FL_ZERO_RANGE :
+ FALLOC_FL_PUNCH_HOLE);
+}
+
+static int raw_file_fmt_discard(struct xloop_file_fmt *xlo_fmt,
+ struct request *rq)
+{
+ loff_t pos = __raw_file_fmt_rq_get_pos(xlo_fmt, rq);
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+
+ return __raw_file_fmt_fallocate(xlo, rq, pos, FALLOC_FL_PUNCH_HOLE);
+}
+
+static int raw_file_fmt_flush(struct xloop_file_fmt *xlo_fmt)
+{
+ struct xloop_device *xlo = xloop_file_fmt_get_xlo(xlo_fmt);
+ struct file *file = xlo->xlo_backing_file;
+ int ret = vfs_fsync(file, 0);
+ if (unlikely(ret && ret != -EINVAL))
+ ret = -EIO;
+
+ return ret;
+}
+
+static loff_t raw_file_fmt_sector_size(struct xloop_file_fmt *xlo_fmt,
+ struct file *file, loff_t offset, loff_t sizelimit)
+{
+ loff_t xloopsize;
+
+ /* Compute xloopsize in bytes */
+ xloopsize = i_size_read(file->f_mapping->host);
+ if (offset > 0)
+ xloopsize -= offset;
+ /* offset is beyond i_size, weird but possible */
+ if (xloopsize < 0)
+ return 0;
+
+ if (sizelimit > 0 && sizelimit < xloopsize)
+ xloopsize = sizelimit;
+ /*
+ * Unfortunately, if we want to do I/O on the device,
+ * the number of 512-byte sectors has to fit into a sector_t.
+ */
+ return xloopsize >> 9;
+}
+
+static struct xloop_file_fmt_ops raw_file_fmt_ops = {
+ .init = NULL,
+ .exit = NULL,
+ .read = raw_file_fmt_read,
+ .write = raw_file_fmt_write,
+ .read_aio = raw_file_fmt_read_aio,
+ .write_aio = raw_file_fmt_write_aio,
+ .write_zeros = raw_file_fmt_write_zeros,
+ .discard = raw_file_fmt_discard,
+ .flush = raw_file_fmt_flush,
+ .sector_size = raw_file_fmt_sector_size,
+};
+
+static struct xloop_file_fmt_driver raw_file_fmt_driver = {
+ .name = "RAW",
+ .file_fmt_type = XLO_FILE_FMT_RAW,
+ .ops = &raw_file_fmt_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __init xloop_file_fmt_raw_init(void)
+{
+ pr_info("init xloop device RAW file format driver\n");
+ return xloop_file_fmt_register_driver(&raw_file_fmt_driver);
+}
+
+static void __exit xloop_file_fmt_raw_exit(void)
+{
+ pr_info("exit xloop device RAW file format driver\n");
+ xloop_file_fmt_unregister_driver(&raw_file_fmt_driver);
+}
+
+module_init(xloop_file_fmt_raw_init);
+module_exit(xloop_file_fmt_raw_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manuel Bentele <development@manuel-bentele.de>");
+MODULE_DESCRIPTION("xloop device RAW file format driver");
+MODULE_SOFTDEP("pre: xloop");
+MODULE_VERSION(__stringify(VERSION));
diff --git a/src/kernel/xloop_main.c b/src/kernel/xloop_main.c
new file mode 100644
index 0000000..a3e20a6
--- /dev/null
+++ b/src/kernel/xloop_main.c
@@ -0,0 +1,2245 @@
+/*
+ * xloop_main.c
+ *
+ * Written by Theodore Ts'o, 3/29/93
+ *
+ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
+ * permitted under the GNU General Public License.
+ *
+ * DES encryption plus some minor changes by Werner Almesberger, 30-MAY-1993
+ * more DES encryption plus IDEA encryption by Nicholas J. Leon, June 20, 1996
+ *
+ * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994
+ * Adapted for 1.3.59 kernel - Andries Brouwer, 1 Feb 1996
+ *
+ * Fixed do_xloop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997
+ *
+ * Added devfs support - Richard Gooch <rgooch@atnf.csiro.au> 16-Jan-1998
+ *
+ * Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998
+ *
+ * Loadable modules and other fixes by AK, 1998
+ *
+ * Make real block number available to downstream transfer functions, enables
+ * CBC (and relatives) mode encryption requiring unique IVs per data block.
+ * Reed H. Petty, rhp@draper.net
+ *
+ * Maximum number of xloop devices now dynamic via max_xloop module parameter.
+ * Russell Kroll <rkroll@exploits.org> 19990701
+ *
+ * Maximum number of xloop devices when compiled-in now selectable by passing
+ * max_xloop=<1-255> to the kernel on boot.
+ * Erik I. Bolsø, <eriki@himolde.no>, Oct 31, 1999
+ *
+ * Completely rewrite request handling to be make_request_fn style and
+ * non blocking, pushing work to a helper thread. Lots of fixes from
+ * Al Viro too.
+ * Jens Axboe <axboe@suse.de>, Nov 2000
+ *
+ * Support up to 256 xloop devices
+ * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
+ *
+ * Support for falling back on the write file operation when the address space
+ * operations write_begin is not available on the backing filesystem.
+ * Anton Altaparmakov, 16 Feb 2005
+ *
+ * Support for using file formats.
+ * Manuel Bentele <development@manuel-bentele.de>, 2019
+ *
+ * Still To Fix:
+ * - Advisory locking is ignored here.
+ * - Should use an own CAP_* category instead of CAP_SYS_ADMIN
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/init.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/suspend.h>
+#include <linux/freezer.h>
+#include <linux/mutex.h>
+#include <linux/writeback.h>
+#include <linux/completion.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <linux/splice.h>
+#include <linux/sysfs.h>
+#include <linux/miscdevice.h>
+#include <linux/falloc.h>
+#include <linux/uio.h>
+#include <linux/ioprio.h>
+#include <linux/blk-cgroup.h>
+#include <linux/version.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#include "xloop_file_fmt.h"
+#include "xloop_main.h"
+
+#include <linux/uaccess.h>
+
+static DEFINE_IDR(xloop_index_idr);
+static DEFINE_MUTEX(xloop_ctl_mutex);
+
+static int max_part;
+static int part_shift;
+
+struct device *xloop_device_to_dev(struct xloop_device *xlo)
+{
+ return disk_to_dev(xlo->xlo_disk);
+}
+EXPORT_SYMBOL(xloop_device_to_dev);
+
+static int transfer_xor(struct xloop_device *xlo, int cmd,
+ struct page *raw_page, unsigned raw_off,
+ struct page *xloop_page, unsigned xloop_off,
+ int size, sector_t real_block)
+{
+ char *raw_buf = kmap_atomic(raw_page) + raw_off;
+ char *xloop_buf = kmap_atomic(xloop_page) + xloop_off;
+ char *in, *out, *key;
+ int i, keysize;
+
+ if (cmd == READ) {
+ in = raw_buf;
+ out = xloop_buf;
+ } else {
+ in = xloop_buf;
+ out = raw_buf;
+ }
+
+ key = xlo->xlo_encrypt_key;
+ keysize = xlo->xlo_encrypt_key_size;
+ for (i = 0; i < size; i++)
+ *out++ = *in++ ^ key[(i & 511) % keysize];
+
+ kunmap_atomic(xloop_buf);
+ kunmap_atomic(raw_buf);
+ cond_resched();
+ return 0;
+}
+
+static int xor_init(struct xloop_device *xlo, const struct xloop_info64 *info)
+{
+ if (unlikely(info->xlo_encrypt_key_size <= 0))
+ return -EINVAL;
+ return 0;
+}
+
+static struct xloop_func_table none_funcs = {
+ .number = XLO_CRYPT_NONE,
+};
+
+static struct xloop_func_table xor_funcs = {
+ .number = XLO_CRYPT_XOR,
+ .transfer = transfer_xor,
+ .init = xor_init
+};
+
+/* xfer_funcs[0] is special - its release function is never called */
+static struct xloop_func_table *xfer_funcs[MAX_XLO_CRYPT] = {
+ &none_funcs,
+ &xor_funcs
+};
+
+static loff_t get_xloop_size(struct xloop_device *xlo, struct file *file)
+{
+ return xloop_file_fmt_sector_size(xlo->xlo_fmt, file, xlo->xlo_offset,
+ xlo->xlo_sizelimit);
+}
+
+static void __xloop_update_dio(struct xloop_device *xlo, bool dio)
+{
+ struct file *file = xlo->xlo_backing_file;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ unsigned short sb_bsize = 0;
+ unsigned dio_align = 0;
+ bool use_dio;
+
+ if (inode->i_sb->s_bdev) {
+ sb_bsize = bdev_logical_block_size(inode->i_sb->s_bdev);
+ dio_align = sb_bsize - 1;
+ }
+
+ /*
+ * We support direct I/O only if xlo_offset is aligned with the
+ * logical I/O size of backing device, and the logical block
+ * size of xloop is bigger than the backing device's and the xloop
+ * needn't transform transfer.
+ *
+ * TODO: the above condition may be loosed in the future, and
+ * direct I/O may be switched runtime at that time because most
+ * of requests in sane applications should be PAGE_SIZE aligned
+ */
+ if (dio) {
+ if (queue_logical_block_size(xlo->xlo_queue) >= sb_bsize &&
+ !(xlo->xlo_offset & dio_align) &&
+ mapping->a_ops->direct_IO &&
+ !xlo->transfer)
+ use_dio = true;
+ else
+ use_dio = false;
+ } else {
+ use_dio = false;
+ }
+
+ if (xlo->use_dio == use_dio)
+ return;
+
+ /* flush dirty pages before changing direct IO */
+ xloop_file_fmt_flush(xlo->xlo_fmt);
+
+ /*
+ * The flag of XLO_FLAGS_DIRECT_IO is handled similarly with
+ * XLO_FLAGS_READ_ONLY, both are set from kernel, and losetup
+ * will get updated by ioctl(XLOOP_GET_STATUS)
+ */
+ if (xlo->xlo_state == Xlo_bound)
+ blk_mq_freeze_queue(xlo->xlo_queue);
+ xlo->use_dio = use_dio;
+ if (use_dio) {
+ blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, xlo->xlo_queue);
+ xlo->xlo_flags |= XLO_FLAGS_DIRECT_IO;
+ } else {
+ blk_queue_flag_set(QUEUE_FLAG_NOMERGES, xlo->xlo_queue);
+ xlo->xlo_flags &= ~XLO_FLAGS_DIRECT_IO;
+ }
+ if (xlo->xlo_state == Xlo_bound)
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+}
+
+/**
+ * xloop_validate_block_size() - validates the passed in block size
+ * @bsize: size to validate
+ */
+static int
+xloop_validate_block_size(unsigned short bsize)
+{
+ if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * xloop_set_size() - sets device size and notifies userspace
+ * @xlo: struct xloop_device to set the size for
+ * @size: new size of the xloop device
+ *
+ * Callers must validate that the size passed into this function fits into
+ * a sector_t, eg using xloop_validate_size()
+ */
+static void xloop_set_size(struct xloop_device *xlo, loff_t size)
+{
+ struct block_device *bdev = xlo->xlo_device;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)
+ sector_t capacity;
+#endif
+
+ bd_set_size(bdev, size << SECTOR_SHIFT);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
+ set_capacity_revalidate_and_notify(xlo->xlo_disk, size, false);
+#else
+ capacity = get_capacity(xlo->xlo_disk);
+ set_capacity(xlo->xlo_disk, size);
+ if (capacity != size && capacity != 0 && size != 0) {
+ char *envp[] = { "RESIZE=1", NULL };
+ kobject_uevent_env(&disk_to_dev(xlo->xlo_disk)->kobj, KOBJ_CHANGE,
+ envp);
+ }
+#endif
+}
+
+static void xlo_complete_rq(struct request *rq)
+{
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ blk_status_t ret = BLK_STS_OK;
+
+ if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
+ req_op(rq) != REQ_OP_READ) {
+ if (cmd->ret < 0)
+ ret = errno_to_blk_status(cmd->ret);
+ goto end_io;
+ }
+
+ /*
+ * Short READ - if we got some data, advance our request and
+ * retry it. If we got no data, end the rest with EIO.
+ */
+ if (cmd->ret) {
+ blk_update_request(rq, BLK_STS_OK, cmd->ret);
+ cmd->ret = 0;
+ blk_mq_requeue_request(rq, true);
+ } else {
+ if (cmd->use_aio) {
+ struct bio *bio = rq->bio;
+
+ while (bio) {
+ zero_fill_bio(bio);
+ bio = bio->bi_next;
+ }
+ }
+ ret = BLK_STS_IOERR;
+end_io:
+ blk_mq_end_request(rq, ret);
+ }
+}
+
+static int do_req_filebacked(struct xloop_device *xlo, struct request *rq)
+{
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
+ /*
+ * xlo_write_simple and xlo_read_simple should have been covered
+ * by io submit style function like xlo_rw_aio(), one blocker
+ * is that xlo_read_simple() need to call flush_dcache_page after
+ * the page is written from kernel, and it isn't easy to handle
+ * this in io submit style function which submits all segments
+ * of the req at one time. And direct read IO doesn't need to
+ * run flush_dcache_page().
+ */
+ switch (req_op(rq)) {
+ case REQ_OP_FLUSH:
+ return xloop_file_fmt_flush(xlo->xlo_fmt);
+ case REQ_OP_WRITE_ZEROES:
+ return xloop_file_fmt_write_zeros(xlo->xlo_fmt, rq);
+ case REQ_OP_DISCARD:
+ return xloop_file_fmt_discard(xlo->xlo_fmt, rq);
+ case REQ_OP_WRITE:
+ if (cmd->use_aio)
+ return xloop_file_fmt_write_aio(xlo->xlo_fmt, rq);
+ else
+ return xloop_file_fmt_write(xlo->xlo_fmt, rq);
+ case REQ_OP_READ:
+ if (cmd->use_aio)
+ return xloop_file_fmt_read_aio(xlo->xlo_fmt, rq);
+ else
+ return xloop_file_fmt_read(xlo->xlo_fmt, rq);
+ default:
+ WARN_ON_ONCE(1);
+ return -EIO;
+ }
+}
+
+static inline void xloop_update_dio(struct xloop_device *xlo)
+{
+ __xloop_update_dio(xlo, (xlo->xlo_backing_file->f_flags & O_DIRECT) |
+ xlo->use_dio);
+}
+
+static void xloop_reread_partitions(struct xloop_device *xlo,
+ struct block_device *bdev)
+{
+ int rc;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+ mutex_lock(&bdev->bd_mutex);
+ rc = bdev_disk_changed(bdev, false);
+ mutex_unlock(&bdev->bd_mutex);
+#else
+ rc = blkdev_reread_part(bdev);
+#endif
+ if (rc)
+ dev_warn(xloop_device_to_dev(xlo), "partition scan failed (rc=%d)\n",
+ rc);
+}
+
+static inline int is_xloop_device(struct file *file)
+{
+ struct inode *i = file->f_mapping->host;
+
+ return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == XLOOP_MAJOR;
+}
+
+static int xloop_validate_file(struct file *file, struct block_device *bdev)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct file *f = file;
+
+ /* Avoid recursion */
+ while (is_xloop_device(f)) {
+ struct xloop_device *l;
+
+ if (f->f_mapping->host->i_bdev == bdev)
+ return -EBADF;
+
+ l = f->f_mapping->host->i_bdev->bd_disk->private_data;
+ if (l->xlo_state != Xlo_bound) {
+ return -EINVAL;
+ }
+ f = l->xlo_backing_file;
+ }
+ if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * xloop_change_fd switched the backing store of a xloopback device to
+ * a new file. This is useful for operating system installers to free up
+ * the original file and in High Availability environments to switch to
+ * an alternative location for the content in case of server meltdown.
+ * This can only work if the xloop device is used read-only, and if the
+ * new backing store is the same size and type as the old backing store.
+ */
+static int xloop_change_fd(struct xloop_device *xlo, struct block_device *bdev,
+ unsigned int arg)
+{
+ struct file *file = NULL, *old_file;
+ int error;
+ bool partscan;
+
+ error = mutex_lock_killable(&xloop_ctl_mutex);
+ if (error)
+ return error;
+ error = -ENXIO;
+ if (xlo->xlo_state != Xlo_bound)
+ goto out_err;
+
+ /* the xloop device has to be read-only */
+ error = -EINVAL;
+ if (!(xlo->xlo_flags & XLO_FLAGS_READ_ONLY))
+ goto out_err;
+
+ error = -EBADF;
+ file = fget(arg);
+ if (!file)
+ goto out_err;
+
+ error = xloop_validate_file(file, bdev);
+ if (error)
+ goto out_err;
+
+ old_file = xlo->xlo_backing_file;
+
+ error = -EINVAL;
+
+ /* size of the new backing store needs to be the same */
+ if (get_xloop_size(xlo, file) != get_xloop_size(xlo, old_file))
+ goto out_err;
+
+ /* and ... switch */
+ blk_mq_freeze_queue(xlo->xlo_queue);
+ mapping_set_gfp_mask(old_file->f_mapping, xlo->old_gfp_mask);
+ xlo->xlo_backing_file = file;
+ xlo->old_gfp_mask = mapping_gfp_mask(file->f_mapping);
+ mapping_set_gfp_mask(file->f_mapping,
+ xlo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+ xloop_update_dio(xlo);
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+ partscan = xlo->xlo_flags & XLO_FLAGS_PARTSCAN;
+ mutex_unlock(&xloop_ctl_mutex);
+ /*
+ * We must drop file reference outside of xloop_ctl_mutex as dropping
+ * the file ref can take bd_mutex which creates circular locking
+ * dependency.
+ */
+ fput(old_file);
+ if (partscan)
+ xloop_reread_partitions(xlo, bdev);
+ return 0;
+
+out_err:
+ mutex_unlock(&xloop_ctl_mutex);
+ if (file)
+ fput(file);
+ return error;
+}
+
+/* xloop sysfs attributes */
+
+static ssize_t xloop_attr_show(struct device *dev, char *page,
+ ssize_t (*callback)(struct xloop_device *, char *))
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct xloop_device *xlo = disk->private_data;
+
+ return callback(xlo, page);
+}
+
+#define XLOOP_ATTR_RO(_name) \
+static ssize_t xloop_attr_##_name##_show(struct xloop_device *, char *); \
+static ssize_t xloop_attr_do_show_##_name(struct device *d, \
+ struct device_attribute *attr, char *b) \
+{ \
+ return xloop_attr_show(d, b, xloop_attr_##_name##_show); \
+} \
+static struct device_attribute xloop_attr_##_name = \
+ __ATTR(_name, 0444, xloop_attr_do_show_##_name, NULL);
+
+static ssize_t xloop_attr_backing_file_show(struct xloop_device *xlo, char *buf)
+{
+ ssize_t ret;
+ char *p = NULL;
+
+ spin_lock_irq(&xlo->xlo_lock);
+ if (xlo->xlo_backing_file)
+ p = file_path(xlo->xlo_backing_file, buf, PAGE_SIZE - 1);
+ spin_unlock_irq(&xlo->xlo_lock);
+
+ if (IS_ERR_OR_NULL(p))
+ ret = PTR_ERR(p);
+ else {
+ ret = strlen(p);
+ memmove(buf, p, ret);
+ buf[ret++] = '\n';
+ buf[ret] = 0;
+ }
+
+ return ret;
+}
+
+static ssize_t xloop_attr_file_fmt_type_show(struct xloop_device *xlo,
+ char *buf)
+{
+ ssize_t len = 0;
+
+ len = xloop_file_fmt_print_type(xlo->xlo_fmt->file_fmt_type, buf);
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t xloop_attr_offset_show(struct xloop_device *xlo, char *buf)
+{
+ return sprintf(buf, "%llu\n", (unsigned long long)xlo->xlo_offset);
+}
+
+static ssize_t xloop_attr_sizelimit_show(struct xloop_device *xlo, char *buf)
+{
+ return sprintf(buf, "%llu\n", (unsigned long long)xlo->xlo_sizelimit);
+}
+
+static ssize_t xloop_attr_autoclear_show(struct xloop_device *xlo, char *buf)
+{
+ int autoclear = (xlo->xlo_flags & XLO_FLAGS_AUTOCLEAR);
+
+ return sprintf(buf, "%s\n", autoclear ? "1" : "0");
+}
+
+static ssize_t xloop_attr_partscan_show(struct xloop_device *xlo, char *buf)
+{
+ int partscan = (xlo->xlo_flags & XLO_FLAGS_PARTSCAN);
+
+ return sprintf(buf, "%s\n", partscan ? "1" : "0");
+}
+
+static ssize_t xloop_attr_dio_show(struct xloop_device *xlo, char *buf)
+{
+ int dio = (xlo->xlo_flags & XLO_FLAGS_DIRECT_IO);
+
+ return sprintf(buf, "%s\n", dio ? "1" : "0");
+}
+
+XLOOP_ATTR_RO(backing_file);
+XLOOP_ATTR_RO(file_fmt_type);
+XLOOP_ATTR_RO(offset);
+XLOOP_ATTR_RO(sizelimit);
+XLOOP_ATTR_RO(autoclear);
+XLOOP_ATTR_RO(partscan);
+XLOOP_ATTR_RO(dio);
+
+static struct attribute *xloop_attrs[] = {
+ &xloop_attr_backing_file.attr,
+ &xloop_attr_file_fmt_type.attr,
+ &xloop_attr_offset.attr,
+ &xloop_attr_sizelimit.attr,
+ &xloop_attr_autoclear.attr,
+ &xloop_attr_partscan.attr,
+ &xloop_attr_dio.attr,
+ NULL,
+};
+
+static struct attribute_group xloop_attribute_group = {
+ .name = "xloop",
+ .attrs= xloop_attrs,
+};
+
+static void xloop_sysfs_init(struct xloop_device *xlo)
+{
+ xlo->sysfs_inited = !sysfs_create_group(&disk_to_dev(xlo->xlo_disk)->kobj,
+ &xloop_attribute_group);
+}
+
+static void xloop_sysfs_exit(struct xloop_device *xlo)
+{
+ if (xlo->sysfs_inited)
+ sysfs_remove_group(&disk_to_dev(xlo->xlo_disk)->kobj,
+ &xloop_attribute_group);
+}
+
+static void xloop_config_discard(struct xloop_device *xlo)
+{
+ struct file *file = xlo->xlo_backing_file;
+ struct inode *inode = file->f_mapping->host;
+ struct request_queue *q = xlo->xlo_queue;
+ u32 granularity, max_discard_sectors;
+
+ /*
+ * If the backing device is a block device, mirror its zeroing
+ * capability. Set the discard sectors to the block device's zeroing
+ * capabilities because xloop discards result in blkdev_issue_zeroout(),
+ * not blkdev_issue_discard(). This maintains consistent behavior with
+ * file-backed xloop devices: discarded regions read back as zero.
+ */
+ if (S_ISBLK(inode->i_mode) && !xlo->xlo_encrypt_key_size) {
+ struct request_queue *backingq;
+
+ backingq = bdev_get_queue(inode->i_bdev);
+
+ max_discard_sectors = backingq->limits.max_write_zeroes_sectors;
+ granularity = backingq->limits.discard_granularity ?:
+ queue_physical_block_size(backingq);
+
+ /*
+ * We use punch hole to reclaim the free space used by the
+ * image a.k.a. discard. However we do not support discard if
+ * encryption is enabled, because it may give an attacker
+ * useful information.
+ */
+ } else if (!file->f_op->fallocate || xlo->xlo_encrypt_key_size) {
+ max_discard_sectors = 0;
+ granularity = 0;
+
+ } else {
+ max_discard_sectors = UINT_MAX >> 9;
+ granularity = inode->i_sb->s_blocksize;
+ }
+
+ if (max_discard_sectors) {
+ q->limits.discard_granularity = granularity;
+ blk_queue_max_discard_sectors(q, max_discard_sectors);
+ blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+ } else {
+ q->limits.discard_granularity = 0;
+ blk_queue_max_discard_sectors(q, 0);
+ blk_queue_max_write_zeroes_sectors(q, 0);
+ blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
+ }
+ q->limits.discard_alignment = 0;
+}
+
+static void xloop_unprepare_queue(struct xloop_device *xlo)
+{
+ kthread_flush_worker(&xlo->worker);
+ kthread_stop(xlo->worker_task);
+}
+
+static int xloop_kthread_worker_fn(void *worker_ptr)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
+#else
+ current->flags |= PF_LESS_THROTTLE | PF_MEMALLOC_NOIO;
+#endif
+ return kthread_worker_fn(worker_ptr);
+}
+
+static int xloop_prepare_queue(struct xloop_device *xlo)
+{
+ kthread_init_worker(&xlo->worker);
+ xlo->worker_task = kthread_run(xloop_kthread_worker_fn,
+ &xlo->worker, "xloop%d", xlo->xlo_number);
+ if (IS_ERR(xlo->worker_task))
+ return -ENOMEM;
+ set_user_nice(xlo->worker_task, MIN_NICE);
+ return 0;
+}
+
+static void xloop_update_rotational(struct xloop_device *xlo)
+{
+ struct file *file = xlo->xlo_backing_file;
+ struct inode *file_inode = file->f_mapping->host;
+ struct block_device *file_bdev = file_inode->i_sb->s_bdev;
+ struct request_queue *q = xlo->xlo_queue;
+ bool nonrot = true;
+
+ /* not all filesystems (e.g. tmpfs) have a sb->s_bdev */
+ if (file_bdev)
+ nonrot = blk_queue_nonrot(bdev_get_queue(file_bdev));
+
+ if (nonrot)
+ blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
+ else
+ blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
+}
+
+static int
+xloop_release_xfer(struct xloop_device *xlo)
+{
+ int err = 0;
+ struct xloop_func_table *xfer = xlo->xlo_encryption;
+
+ if (xfer) {
+ if (xfer->release)
+ err = xfer->release(xlo);
+ xlo->transfer = NULL;
+ xlo->xlo_encryption = NULL;
+ module_put(xfer->owner);
+ }
+ return err;
+}
+
+static int
+xloop_init_xfer(struct xloop_device *xlo, struct xloop_func_table *xfer,
+ const struct xloop_info64 *i)
+{
+ int err = 0;
+
+ if (xfer) {
+ struct module *owner = xfer->owner;
+
+ if (!try_module_get(owner))
+ return -EINVAL;
+ if (xfer->init)
+ err = xfer->init(xlo, i);
+ if (err)
+ module_put(owner);
+ else
+ xlo->xlo_encryption = xfer;
+ }
+ return err;
+}
+
+/**
+ * xloop_set_status_from_info - configure device from xloop_info
+ * @xlo: struct xloop_device to configure
+ * @info: struct xloop_info64 to configure the device with
+ *
+ * Configures the xloop device parameters according to the passed
+ * in xloop_info64 configuration.
+ */
+static int
+xloop_set_status_from_info(struct xloop_device *xlo,
+ const struct xloop_info64 *info)
+{
+ int err;
+ struct xloop_func_table *xfer;
+ kuid_t uid = current_uid();
+
+ if ((unsigned int) info->xlo_encrypt_key_size > XLO_KEY_SIZE)
+ return -EINVAL;
+
+ err = xloop_release_xfer(xlo);
+ if (err)
+ return err;
+
+ if (info->xlo_encrypt_type) {
+ unsigned int type = info->xlo_encrypt_type;
+
+ if (type >= MAX_XLO_CRYPT)
+ return -EINVAL;
+ xfer = xfer_funcs[type];
+ if (xfer == NULL)
+ return -EINVAL;
+ } else
+ xfer = NULL;
+
+ err = xloop_init_xfer(xlo, xfer, info);
+ if (err)
+ return err;
+
+ xlo->xlo_offset = info->xlo_offset;
+ xlo->xlo_sizelimit = info->xlo_sizelimit;
+ memcpy(xlo->xlo_file_name, info->xlo_file_name, XLO_NAME_SIZE);
+ memcpy(xlo->xlo_crypt_name, info->xlo_crypt_name, XLO_NAME_SIZE);
+ xlo->xlo_file_name[XLO_NAME_SIZE-1] = 0;
+ xlo->xlo_crypt_name[XLO_NAME_SIZE-1] = 0;
+
+ if (!xfer)
+ xfer = &none_funcs;
+ xlo->transfer = xfer->transfer;
+ xlo->ioctl = xfer->ioctl;
+
+ xlo->xlo_flags = info->xlo_flags;
+
+ xlo->xlo_encrypt_key_size = info->xlo_encrypt_key_size;
+ xlo->xlo_init[0] = info->xlo_init[0];
+ xlo->xlo_init[1] = info->xlo_init[1];
+ if (info->xlo_encrypt_key_size) {
+ memcpy(xlo->xlo_encrypt_key, info->xlo_encrypt_key,
+ info->xlo_encrypt_key_size);
+ xlo->xlo_key_owner = uid;
+ }
+
+ return 0;
+}
+
+static int xloop_configure(struct xloop_device *xlo, fmode_t mode,
+ struct block_device *bdev,
+ const struct xloop_config *config)
+{
+ struct file *file;
+ struct inode *inode;
+ struct address_space *mapping;
+ struct block_device *claimed_bdev = NULL;
+ int error;
+ loff_t size;
+ bool partscan;
+ unsigned short bsize;
+
+ /* This is safe, since we have a reference from open(). */
+ __module_get(THIS_MODULE);
+
+ error = -EBADF;
+ file = fget(config->fd);
+ if (!file)
+ goto out;
+
+ /*
+ * If we don't hold exclusive handle for the device, upgrade to it
+ * here to avoid changing device under exclusive owner.
+ */
+ if (!(mode & FMODE_EXCL)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+ claimed_bdev = bdev->bd_contains;
+ error = bd_prepare_to_claim(bdev, claimed_bdev, xloop_configure);
+ if (error)
+ goto out_putf;
+#else
+ claimed_bdev = bd_start_claiming(bdev, xloop_configure);
+ if (IS_ERR(claimed_bdev)) {
+ error = PTR_ERR(claimed_bdev);
+ goto out_putf;
+ }
+#endif
+ }
+
+ error = mutex_lock_killable(&xloop_ctl_mutex);
+ if (error)
+ goto out_bdev;
+
+ error = -EBUSY;
+ if (xlo->xlo_state != Xlo_unbound)
+ goto out_unlock;
+
+ error = xloop_validate_file(file, bdev);
+ if (error)
+ goto out_unlock;
+
+ mapping = file->f_mapping;
+ inode = mapping->host;
+
+ if ((config->info.xlo_flags & ~XLOOP_CONFIGURE_SETTABLE_FLAGS) != 0) {
+ error = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (config->block_size) {
+ error = xloop_validate_block_size(config->block_size);
+ if (error)
+ goto out_unlock;
+ }
+
+ error = xloop_set_status_from_info(xlo, &config->info);
+ if (error)
+ goto out_unlock;
+
+ if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) ||
+ !file->f_op->write_iter)
+ xlo->xlo_flags |= XLO_FLAGS_READ_ONLY;
+
+ error = xloop_prepare_queue(xlo);
+ if (error)
+ goto out_unlock;
+
+ error = xloop_file_fmt_init(xlo->xlo_fmt,
+ config->info.xlo_file_fmt_type);
+ if (error)
+ goto out_unlock;
+
+ set_device_ro(bdev, (xlo->xlo_flags & XLO_FLAGS_READ_ONLY) != 0);
+
+ xlo->use_dio = xlo->xlo_flags & XLO_FLAGS_DIRECT_IO;
+ xlo->xlo_device = bdev;
+ xlo->xlo_backing_file = file;
+ xlo->old_gfp_mask = mapping_gfp_mask(mapping);
+ mapping_set_gfp_mask(mapping, xlo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+
+ if (!(xlo->xlo_flags & XLO_FLAGS_READ_ONLY) && file->f_op->fsync)
+ blk_queue_write_cache(xlo->xlo_queue, true, false);
+
+ if (config->block_size)
+ bsize = config->block_size;
+ else if ((xlo->xlo_backing_file->f_flags & O_DIRECT) && inode->i_sb->s_bdev)
+ /* In case of direct I/O, match underlying block size */
+ bsize = bdev_logical_block_size(inode->i_sb->s_bdev);
+ else
+ bsize = 512;
+
+ blk_queue_logical_block_size(xlo->xlo_queue, bsize);
+ blk_queue_physical_block_size(xlo->xlo_queue, bsize);
+ blk_queue_io_min(xlo->xlo_queue, bsize);
+
+ xloop_update_rotational(xlo);
+ xloop_update_dio(xlo);
+ xloop_sysfs_init(xlo);
+
+ size = get_xloop_size(xlo, file);
+ xloop_set_size(xlo, size);
+
+ set_blocksize(bdev, S_ISBLK(inode->i_mode) ?
+ block_size(inode->i_bdev) : PAGE_SIZE);
+
+ xlo->xlo_state = Xlo_bound;
+ if (part_shift)
+ xlo->xlo_flags |= XLO_FLAGS_PARTSCAN;
+ partscan = xlo->xlo_flags & XLO_FLAGS_PARTSCAN;
+ if (partscan)
+ xlo->xlo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
+
+ /* Grab the block_device to prevent its destruction after we
+ * put /dev/xloopXX inode. Later in __xloop_clr_fd() we bdput(bdev).
+ */
+ bdgrab(bdev);
+ mutex_unlock(&xloop_ctl_mutex);
+ if (partscan)
+ xloop_reread_partitions(xlo, bdev);
+ if (claimed_bdev)
+ bd_abort_claiming(bdev, claimed_bdev, xloop_configure);
+ return 0;
+
+out_unlock:
+ mutex_unlock(&xloop_ctl_mutex);
+out_bdev:
+ if (claimed_bdev)
+ bd_abort_claiming(bdev, claimed_bdev, xloop_configure);
+out_putf:
+ fput(file);
+out:
+ /* This is safe: open() is still holding a reference. */
+ module_put(THIS_MODULE);
+ return error;
+}
+
+static int __xloop_clr_fd(struct xloop_device *xlo, bool release)
+{
+ struct file *filp = NULL;
+ gfp_t gfp = xlo->old_gfp_mask;
+ struct block_device *bdev = xlo->xlo_device;
+ int err = 0;
+ bool partscan = false;
+ int xlo_number;
+
+ mutex_lock(&xloop_ctl_mutex);
+ if (WARN_ON_ONCE(xlo->xlo_state != Xlo_rundown)) {
+ err = -ENXIO;
+ goto out_unlock;
+ }
+
+ filp = xlo->xlo_backing_file;
+ if (filp == NULL) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* freeze request queue during the transition */
+ blk_mq_freeze_queue(xlo->xlo_queue);
+
+ xloop_file_fmt_exit(xlo->xlo_fmt);
+
+ spin_lock_irq(&xlo->xlo_lock);
+ xlo->xlo_backing_file = NULL;
+ spin_unlock_irq(&xlo->xlo_lock);
+
+ xloop_release_xfer(xlo);
+ xlo->transfer = NULL;
+ xlo->ioctl = NULL;
+ xlo->xlo_device = NULL;
+ xlo->xlo_encryption = NULL;
+ xlo->xlo_offset = 0;
+ xlo->xlo_sizelimit = 0;
+ xlo->xlo_encrypt_key_size = 0;
+ memset(xlo->xlo_encrypt_key, 0, XLO_KEY_SIZE);
+ memset(xlo->xlo_crypt_name, 0, XLO_NAME_SIZE);
+ memset(xlo->xlo_file_name, 0, XLO_NAME_SIZE);
+ blk_queue_logical_block_size(xlo->xlo_queue, 512);
+ blk_queue_physical_block_size(xlo->xlo_queue, 512);
+ blk_queue_io_min(xlo->xlo_queue, 512);
+ if (bdev) {
+ bdput(bdev);
+ invalidate_bdev(bdev);
+ bdev->bd_inode->i_mapping->wb_err = 0;
+ }
+ set_capacity(xlo->xlo_disk, 0);
+ xloop_sysfs_exit(xlo);
+ if (bdev) {
+ bd_set_size(bdev, 0);
+ /* let user-space know about this change */
+ kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
+ }
+ mapping_set_gfp_mask(filp->f_mapping, gfp);
+ /* This is safe: open() is still holding a reference. */
+ module_put(THIS_MODULE);
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+
+ partscan = xlo->xlo_flags & XLO_FLAGS_PARTSCAN && bdev;
+ xlo_number = xlo->xlo_number;
+ xloop_unprepare_queue(xlo);
+out_unlock:
+ mutex_unlock(&xloop_ctl_mutex);
+ if (partscan) {
+ /*
+ * bd_mutex has been held already in release path, so don't
+ * acquire it if this function is called in such case.
+ *
+ * If the reread partition isn't from release path, xlo_refcnt
+ * must be at least one and it can only become zero when the
+ * current holder is released.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+ if (!release)
+ mutex_lock(&bdev->bd_mutex);
+ err = bdev_disk_changed(bdev, false);
+#else
+ err = blkdev_reread_part(bdev);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+ if (!release)
+ mutex_unlock(&bdev->bd_mutex);
+#endif
+ if (err)
+ dev_warn(xloop_device_to_dev(xlo), "partition scan failed "
+ "(rc=%d)\n", err);
+ /* Device is gone, no point in returning error */
+ err = 0;
+ }
+
+ /*
+ * xlo->xlo_state is set to Xlo_unbound here after above partscan has
+ * finished.
+ *
+ * There cannot be anybody else entering __xloop_clr_fd() as
+ * xlo->xlo_backing_file is already cleared and Xlo_rundown state
+ * protects us from all the other places trying to change the 'xlo'
+ * device.
+ */
+ mutex_lock(&xloop_ctl_mutex);
+ xlo->xlo_flags = 0;
+ if (!part_shift)
+ xlo->xlo_disk->flags |= GENHD_FL_NO_PART_SCAN;
+ xlo->xlo_state = Xlo_unbound;
+ mutex_unlock(&xloop_ctl_mutex);
+
+ /*
+ * Need not hold xloop_ctl_mutex to fput backing file.
+ * Calling fput holding xloop_ctl_mutex triggers a circular
+ * lock dependency possibility warning as fput can take
+ * bd_mutex which is usually taken before xloop_ctl_mutex.
+ */
+ if (filp)
+ fput(filp);
+ return err;
+}
+
+static int xloop_clr_fd(struct xloop_device *xlo)
+{
+ int err;
+
+ err = mutex_lock_killable(&xloop_ctl_mutex);
+ if (err)
+ return err;
+ if (xlo->xlo_state != Xlo_bound) {
+ mutex_unlock(&xloop_ctl_mutex);
+ return -ENXIO;
+ }
+ /*
+ * If we've explicitly asked to tear down the xloop device,
+ * and it has an elevated reference count, set it for auto-teardown when
+ * the last reference goes away. This stops $!~#$@ udev from
+ * preventing teardown because it decided that it needs to run blkid on
+ * the xloopback device whenever they appear. xfstests is notorious for
+ * failing tests because blkid via udev races with a losetup
+ * <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d
+ * command to fail with EBUSY.
+ */
+ if (atomic_read(&xlo->xlo_refcnt) > 1) {
+ xlo->xlo_flags |= XLO_FLAGS_AUTOCLEAR;
+ mutex_unlock(&xloop_ctl_mutex);
+ return 0;
+ }
+ xlo->xlo_state = Xlo_rundown;
+ mutex_unlock(&xloop_ctl_mutex);
+
+ return __xloop_clr_fd(xlo, false);
+}
+
+static int
+xloop_set_status(struct xloop_device *xlo, const struct xloop_info64 *info)
+{
+ int err;
+ struct block_device *bdev;
+ kuid_t uid = current_uid();
+ int prev_xlo_flags;
+ bool partscan = false;
+ bool size_changed = false;
+
+ err = mutex_lock_killable(&xloop_ctl_mutex);
+ if (err)
+ return err;
+ if (xlo->xlo_encrypt_key_size &&
+ !uid_eq(xlo->xlo_key_owner, uid) &&
+ !capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto out_unlock;
+ }
+ if (xlo->xlo_state != Xlo_bound) {
+ err = -ENXIO;
+ goto out_unlock;
+ }
+
+ if (xlo->xlo_offset != info->xlo_offset ||
+ xlo->xlo_sizelimit != info->xlo_sizelimit) {
+ size_changed = true;
+ sync_blockdev(xlo->xlo_device);
+ invalidate_bdev(xlo->xlo_device);
+ }
+
+ /* I/O need to be drained during transfer transition */
+ blk_mq_freeze_queue(xlo->xlo_queue);
+
+ if (size_changed && xlo->xlo_device->bd_inode->i_mapping->nrpages) {
+ /* If any pages were dirtied after invalidate_bdev(), try again */
+ err = -EAGAIN;
+ dev_warn(xloop_device_to_dev(xlo), "xloop device has still dirty "
+ "pages (nrpages=%lu)\n",
+ xlo->xlo_device->bd_inode->i_mapping->nrpages);
+ goto out_unfreeze;
+ }
+
+ prev_xlo_flags = xlo->xlo_flags;
+
+ err = xloop_set_status_from_info(xlo, info);
+ if (err)
+ goto out_unfreeze;
+
+ /* Mask out flags that can't be set using XLOOP_SET_STATUS. */
+ xlo->xlo_flags &= XLOOP_SET_STATUS_SETTABLE_FLAGS;
+ /* For those flags, use the previous values instead */
+ xlo->xlo_flags |= prev_xlo_flags & ~XLOOP_SET_STATUS_SETTABLE_FLAGS;
+ /* For flags that can't be cleared, use previous values too */
+ xlo->xlo_flags |= prev_xlo_flags & ~XLOOP_SET_STATUS_CLEARABLE_FLAGS;
+
+ if (xlo->xlo_fmt->file_fmt_type != info->xlo_file_fmt_type) {
+ /* xloop file format has changed, so change file format driver */
+ err = xloop_file_fmt_change(xlo->xlo_fmt, info->xlo_file_fmt_type);
+ if (err)
+ goto out_unfreeze;
+
+ /* After change of the file format, recalculate the capacity of
+ * the loop device. */
+ size_changed = true;
+ }
+
+ if (size_changed) {
+ loff_t new_size = get_xloop_size(xlo, xlo->xlo_backing_file);
+ xloop_set_size(xlo, new_size);
+ }
+
+ xloop_config_discard(xlo);
+
+ /* update dio if xlo_offset or transfer is changed */
+ __xloop_update_dio(xlo, xlo->use_dio);
+
+out_unfreeze:
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+
+ if (!err && (xlo->xlo_flags & XLO_FLAGS_PARTSCAN) &&
+ !(prev_xlo_flags & XLO_FLAGS_PARTSCAN)) {
+ xlo->xlo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
+ bdev = xlo->xlo_device;
+ partscan = true;
+ }
+out_unlock:
+ mutex_unlock(&xloop_ctl_mutex);
+ if (partscan)
+ xloop_reread_partitions(xlo, bdev);
+
+ return err;
+}
+
+static int
+xloop_get_status(struct xloop_device *xlo, struct xloop_info64 *info)
+{
+ struct path path;
+ struct kstat stat;
+ int ret;
+
+ ret = mutex_lock_killable(&xloop_ctl_mutex);
+ if (ret)
+ return ret;
+ if (xlo->xlo_state != Xlo_bound) {
+ mutex_unlock(&xloop_ctl_mutex);
+ return -ENXIO;
+ }
+
+ memset(info, 0, sizeof(*info));
+ info->xlo_number = xlo->xlo_number;
+ info->xlo_offset = xlo->xlo_offset;
+ info->xlo_sizelimit = xlo->xlo_sizelimit;
+ info->xlo_flags = xlo->xlo_flags;
+ memcpy(info->xlo_file_name, xlo->xlo_file_name, XLO_NAME_SIZE);
+ memcpy(info->xlo_crypt_name, xlo->xlo_crypt_name, XLO_NAME_SIZE);
+ info->xlo_encrypt_type =
+ xlo->xlo_encryption ? xlo->xlo_encryption->number : 0;
+ if (xlo->xlo_encrypt_key_size && capable(CAP_SYS_ADMIN)) {
+ info->xlo_encrypt_key_size = xlo->xlo_encrypt_key_size;
+ memcpy(info->xlo_encrypt_key, xlo->xlo_encrypt_key,
+ xlo->xlo_encrypt_key_size);
+ }
+
+ /* Drop xloop_ctl_mutex while we call into the filesystem. */
+ path = xlo->xlo_backing_file->f_path;
+ path_get(&path);
+ mutex_unlock(&xloop_ctl_mutex);
+ ret = vfs_getattr(&path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT);
+ if (!ret) {
+ info->xlo_device = huge_encode_dev(stat.dev);
+ info->xlo_inode = stat.ino;
+ info->xlo_rdevice = huge_encode_dev(stat.rdev);
+ }
+ path_put(&path);
+ return ret;
+}
+
+static void
+xloop_info64_from_old(const struct xloop_info *info, struct xloop_info64 *info64)
+{
+ memset(info64, 0, sizeof(*info64));
+ info64->xlo_number = info->xlo_number;
+ info64->xlo_device = info->xlo_device;
+ info64->xlo_inode = info->xlo_inode;
+ info64->xlo_rdevice = info->xlo_rdevice;
+ info64->xlo_offset = info->xlo_offset;
+ info64->xlo_sizelimit = 0;
+ info64->xlo_encrypt_type = info->xlo_encrypt_type;
+ info64->xlo_encrypt_key_size = info->xlo_encrypt_key_size;
+ info64->xlo_flags = info->xlo_flags;
+ info64->xlo_init[0] = info->xlo_init[0];
+ info64->xlo_init[1] = info->xlo_init[1];
+ info64->xlo_file_fmt_type = info->xlo_file_fmt_type;
+ if (info->xlo_encrypt_type == XLO_CRYPT_CRYPTOAPI)
+ memcpy(info64->xlo_crypt_name, info->xlo_name, XLO_NAME_SIZE);
+ else
+ memcpy(info64->xlo_file_name, info->xlo_name, XLO_NAME_SIZE);
+ memcpy(info64->xlo_encrypt_key, info->xlo_encrypt_key, XLO_KEY_SIZE);
+}
+
+static int
+xloop_info64_to_old(const struct xloop_info64 *info64, struct xloop_info *info)
+{
+ memset(info, 0, sizeof(*info));
+ info->xlo_number = info64->xlo_number;
+ info->xlo_device = info64->xlo_device;
+ info->xlo_inode = info64->xlo_inode;
+ info->xlo_rdevice = info64->xlo_rdevice;
+ info->xlo_offset = info64->xlo_offset;
+ info->xlo_encrypt_type = info64->xlo_encrypt_type;
+ info->xlo_encrypt_key_size = info64->xlo_encrypt_key_size;
+ info->xlo_flags = info64->xlo_flags;
+ info->xlo_init[0] = info64->xlo_init[0];
+ info->xlo_init[1] = info64->xlo_init[1];
+ info->xlo_file_fmt_type = info64->xlo_file_fmt_type;
+ if (info->xlo_encrypt_type == XLO_CRYPT_CRYPTOAPI)
+ memcpy(info->xlo_name, info64->xlo_crypt_name, XLO_NAME_SIZE);
+ else
+ memcpy(info->xlo_name, info64->xlo_file_name, XLO_NAME_SIZE);
+ memcpy(info->xlo_encrypt_key, info64->xlo_encrypt_key, XLO_KEY_SIZE);
+
+ /* error in case values were truncated */
+ if (info->xlo_device != info64->xlo_device ||
+ info->xlo_rdevice != info64->xlo_rdevice ||
+ info->xlo_inode != info64->xlo_inode ||
+ info->xlo_offset != info64->xlo_offset)
+ return -EOVERFLOW;
+
+ return 0;
+}
+
+static int
+xloop_set_status_old(struct xloop_device *xlo, const struct xloop_info __user *arg)
+{
+ struct xloop_info info;
+ struct xloop_info64 info64;
+
+ if (copy_from_user(&info, arg, sizeof (struct xloop_info)))
+ return -EFAULT;
+ xloop_info64_from_old(&info, &info64);
+ return xloop_set_status(xlo, &info64);
+}
+
+static int
+xloop_set_status64(struct xloop_device *xlo, const struct xloop_info64 __user *arg)
+{
+ struct xloop_info64 info64;
+
+ if (copy_from_user(&info64, arg, sizeof (struct xloop_info64)))
+ return -EFAULT;
+ return xloop_set_status(xlo, &info64);
+}
+
+static int
+xloop_get_status_old(struct xloop_device *xlo, struct xloop_info __user *arg) {
+ struct xloop_info info;
+ struct xloop_info64 info64;
+ int err;
+
+ if (!arg)
+ return -EINVAL;
+ err = xloop_get_status(xlo, &info64);
+ if (!err)
+ err = xloop_info64_to_old(&info64, &info);
+ if (!err && copy_to_user(arg, &info, sizeof(info)))
+ err = -EFAULT;
+
+ return err;
+}
+
+static int
+xloop_get_status64(struct xloop_device *xlo, struct xloop_info64 __user *arg) {
+ struct xloop_info64 info64;
+ int err;
+
+ if (!arg)
+ return -EINVAL;
+ err = xloop_get_status(xlo, &info64);
+ if (!err && copy_to_user(arg, &info64, sizeof(info64)))
+ err = -EFAULT;
+
+ return err;
+}
+
+static int xloop_set_capacity(struct xloop_device *xlo)
+{
+ loff_t size;
+
+ if (unlikely(xlo->xlo_state != Xlo_bound))
+ return -ENXIO;
+
+ size = get_xloop_size(xlo, xlo->xlo_backing_file);
+ xloop_set_size(xlo, size);
+
+ return 0;
+}
+
+static int xloop_set_dio(struct xloop_device *xlo, unsigned long arg)
+{
+ int error = -ENXIO;
+ if (xlo->xlo_state != Xlo_bound)
+ goto out;
+
+ __xloop_update_dio(xlo, !!arg);
+ if (xlo->use_dio == !!arg)
+ return 0;
+ error = -EINVAL;
+ out:
+ return error;
+}
+
+static int xloop_set_block_size(struct xloop_device *xlo, unsigned long arg)
+{
+ int err = 0;
+
+ if (xlo->xlo_state != Xlo_bound)
+ return -ENXIO;
+
+ err = xloop_validate_block_size(arg);
+ if (err)
+ return err;
+
+ if (xlo->xlo_queue->limits.logical_block_size == arg)
+ return 0;
+
+ sync_blockdev(xlo->xlo_device);
+ invalidate_bdev(xlo->xlo_device);
+
+ blk_mq_freeze_queue(xlo->xlo_queue);
+
+ /* invalidate_bdev should have truncated all the pages */
+ if (xlo->xlo_device->bd_inode->i_mapping->nrpages) {
+ err = -EAGAIN;
+ dev_warn(xloop_device_to_dev(xlo), "xloop device has still dirty "
+ "pages (nrpages=%lu)\n",
+ xlo->xlo_device->bd_inode->i_mapping->nrpages);
+ goto out_unfreeze;
+ }
+
+ blk_queue_logical_block_size(xlo->xlo_queue, arg);
+ blk_queue_physical_block_size(xlo->xlo_queue, arg);
+ blk_queue_io_min(xlo->xlo_queue, arg);
+ xloop_update_dio(xlo);
+out_unfreeze:
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+
+ return err;
+}
+
+static int xlo_simple_ioctl(struct xloop_device *xlo, unsigned int cmd,
+ unsigned long arg)
+{
+ int err;
+
+ err = mutex_lock_killable(&xloop_ctl_mutex);
+ if (err)
+ return err;
+ switch (cmd) {
+ case XLOOP_SET_CAPACITY:
+ err = xloop_set_capacity(xlo);
+ break;
+ case XLOOP_SET_DIRECT_IO:
+ err = xloop_set_dio(xlo, arg);
+ break;
+ case XLOOP_SET_BLOCK_SIZE:
+ err = xloop_set_block_size(xlo, arg);
+ break;
+ default:
+ err = xlo->ioctl ? xlo->ioctl(xlo, cmd, arg) : -EINVAL;
+ }
+ mutex_unlock(&xloop_ctl_mutex);
+ return err;
+}
+
+static int xlo_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct xloop_device *xlo = bdev->bd_disk->private_data;
+ void __user *argp = (void __user *) arg;
+ int err;
+
+ switch (cmd) {
+ case XLOOP_SET_FD: {
+ /*
+ * Legacy case - pass in a zeroed out struct xloop_config with
+ * only the file descriptor set , which corresponds with the
+ * default parameters we'd have used otherwise.
+ */
+ struct xloop_config config;
+
+ memset(&config, 0, sizeof(config));
+ config.fd = arg;
+
+ return xloop_configure(xlo, mode, bdev, &config);
+ }
+ case XLOOP_CONFIGURE: {
+ struct xloop_config config;
+
+ if (copy_from_user(&config, argp, sizeof(config)))
+ return -EFAULT;
+
+ return xloop_configure(xlo, mode, bdev, &config);
+ }
+ case XLOOP_CHANGE_FD:
+ return xloop_change_fd(xlo, bdev, arg);
+ case XLOOP_CLR_FD:
+ return xloop_clr_fd(xlo);
+ case XLOOP_SET_STATUS:
+ err = -EPERM;
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) {
+ err = xloop_set_status_old(xlo, argp);
+ }
+ break;
+ case XLOOP_GET_STATUS:
+ return xloop_get_status_old(xlo, argp);
+ case XLOOP_SET_STATUS64:
+ err = -EPERM;
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) {
+ err = xloop_set_status64(xlo, argp);
+ }
+ break;
+ case XLOOP_GET_STATUS64:
+ return xloop_get_status64(xlo, argp);
+ case XLOOP_SET_CAPACITY:
+ case XLOOP_SET_DIRECT_IO:
+ case XLOOP_SET_BLOCK_SIZE:
+ if (!(mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+ fallthrough;
+#else
+ /* fall through */
+#endif
+ default:
+ err = xlo_simple_ioctl(xlo, cmd, arg);
+ break;
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_xloop_info {
+ compat_int_t xlo_number; /* ioctl r/o */
+ compat_dev_t xlo_device; /* ioctl r/o */
+ compat_ulong_t xlo_inode; /* ioctl r/o */
+ compat_dev_t xlo_rdevice; /* ioctl r/o */
+ compat_int_t xlo_offset;
+ compat_int_t xlo_encrypt_type;
+ compat_int_t xlo_encrypt_key_size; /* ioctl w/o */
+ compat_int_t xlo_flags; /* ioctl r/o */
+ char xlo_name[XLO_NAME_SIZE];
+ unsigned char xlo_encrypt_key[XLO_KEY_SIZE]; /* ioctl w/o */
+ compat_ulong_t xlo_init[2];
+ char reserved[4];
+ compat_int_t xlo_file_fmt_type;
+};
+
+/*
+ * Transfer 32-bit compatibility structure in userspace to 64-bit xloop info
+ * - noinlined to reduce stack space usage in main part of driver
+ */
+static noinline int
+xloop_info64_from_compat(const struct compat_xloop_info __user *arg,
+ struct xloop_info64 *info64)
+{
+ struct compat_xloop_info info;
+
+ if (copy_from_user(&info, arg, sizeof(info)))
+ return -EFAULT;
+
+ memset(info64, 0, sizeof(*info64));
+ info64->xlo_number = info.xlo_number;
+ info64->xlo_device = info.xlo_device;
+ info64->xlo_inode = info.xlo_inode;
+ info64->xlo_rdevice = info.xlo_rdevice;
+ info64->xlo_offset = info.xlo_offset;
+ info64->xlo_sizelimit = 0;
+ info64->xlo_encrypt_type = info.xlo_encrypt_type;
+ info64->xlo_encrypt_key_size = info.xlo_encrypt_key_size;
+ info64->xlo_flags = info.xlo_flags;
+ info64->xlo_init[0] = info.xlo_init[0];
+ info64->xlo_init[1] = info.xlo_init[1];
+ info64->xlo_file_fmt_type = info.xlo_file_fmt_type;
+ if (info.xlo_encrypt_type == XLO_CRYPT_CRYPTOAPI)
+ memcpy(info64->xlo_crypt_name, info.xlo_name, XLO_NAME_SIZE);
+ else
+ memcpy(info64->xlo_file_name, info.xlo_name, XLO_NAME_SIZE);
+ memcpy(info64->xlo_encrypt_key, info.xlo_encrypt_key, XLO_KEY_SIZE);
+ return 0;
+}
+
+/*
+ * Transfer 64-bit xloop info to 32-bit compatibility structure in userspace
+ * - noinlined to reduce stack space usage in main part of driver
+ */
+static noinline int
+xloop_info64_to_compat(const struct xloop_info64 *info64,
+ struct compat_xloop_info __user *arg)
+{
+ struct compat_xloop_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.xlo_number = info64->xlo_number;
+ info.xlo_device = info64->xlo_device;
+ info.xlo_inode = info64->xlo_inode;
+ info.xlo_rdevice = info64->xlo_rdevice;
+ info.xlo_offset = info64->xlo_offset;
+ info.xlo_encrypt_type = info64->xlo_encrypt_type;
+ info.xlo_encrypt_key_size = info64->xlo_encrypt_key_size;
+ info.xlo_flags = info64->xlo_flags;
+ info.xlo_init[0] = info64->xlo_init[0];
+ info.xlo_init[1] = info64->xlo_init[1];
+ info.xlo_file_fmt_type = info64->xlo_file_fmt_type;
+ if (info.xlo_encrypt_type == XLO_CRYPT_CRYPTOAPI)
+ memcpy(info.xlo_name, info64->xlo_crypt_name, XLO_NAME_SIZE);
+ else
+ memcpy(info.xlo_name, info64->xlo_file_name, XLO_NAME_SIZE);
+ memcpy(info.xlo_encrypt_key, info64->xlo_encrypt_key, XLO_KEY_SIZE);
+
+ /* error in case values were truncated */
+ if (info.xlo_device != info64->xlo_device ||
+ info.xlo_rdevice != info64->xlo_rdevice ||
+ info.xlo_inode != info64->xlo_inode ||
+ info.xlo_offset != info64->xlo_offset ||
+ info.xlo_init[0] != info64->xlo_init[0] ||
+ info.xlo_init[1] != info64->xlo_init[1] ||
+ info.xlo_file_fmt_type != info64->xlo_file_fmt_type)
+ return -EOVERFLOW;
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+xloop_set_status_compat(struct xloop_device *xlo,
+ const struct compat_xloop_info __user *arg)
+{
+ struct xloop_info64 info64;
+ int ret;
+
+ ret = xloop_info64_from_compat(arg, &info64);
+ if (ret < 0)
+ return ret;
+ return xloop_set_status(xlo, &info64);
+}
+
+static int
+xloop_get_status_compat(struct xloop_device *xlo,
+ struct compat_xloop_info __user *arg)
+{
+ struct xloop_info64 info64;
+ int err;
+
+ if (!arg)
+ return -EINVAL;
+ err = xloop_get_status(xlo, &info64);
+ if (!err)
+ err = xloop_info64_to_compat(&info64, arg);
+ return err;
+}
+
+static int xlo_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct xloop_device *xlo = bdev->bd_disk->private_data;
+ int err;
+
+ switch(cmd) {
+ case XLOOP_SET_STATUS:
+ err = xloop_set_status_compat(xlo,
+ (const struct compat_xloop_info __user *)arg);
+ break;
+ case XLOOP_GET_STATUS:
+ err = xloop_get_status_compat(xlo,
+ (struct compat_xloop_info __user *)arg);
+ break;
+ case XLOOP_SET_CAPACITY:
+ case XLOOP_CLR_FD:
+ case XLOOP_GET_STATUS64:
+ case XLOOP_SET_STATUS64:
+ case XLOOP_CONFIGURE:
+ arg = (unsigned long) compat_ptr(arg);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
+ fallthrough;
+#else
+ /* fall through */
+#endif
+ case XLOOP_SET_FD:
+ case XLOOP_CHANGE_FD:
+ case XLOOP_SET_BLOCK_SIZE:
+ case XLOOP_SET_DIRECT_IO:
+ err = xlo_ioctl(bdev, mode, cmd, arg);
+ break;
+ default:
+ err = -ENOIOCTLCMD;
+ break;
+ }
+ return err;
+}
+#endif
+
+static int xlo_open(struct block_device *bdev, fmode_t mode)
+{
+ struct xloop_device *xlo;
+ int err;
+
+ err = mutex_lock_killable(&xloop_ctl_mutex);
+ if (err)
+ return err;
+ xlo = bdev->bd_disk->private_data;
+ if (!xlo) {
+ err = -ENXIO;
+ goto out;
+ }
+
+ atomic_inc(&xlo->xlo_refcnt);
+out:
+ mutex_unlock(&xloop_ctl_mutex);
+ return err;
+}
+
+static void xlo_release(struct gendisk *disk, fmode_t mode)
+{
+ struct xloop_device *xlo;
+
+ mutex_lock(&xloop_ctl_mutex);
+ xlo = disk->private_data;
+ if (atomic_dec_return(&xlo->xlo_refcnt))
+ goto out_unlock;
+
+ if (xlo->xlo_flags & XLO_FLAGS_AUTOCLEAR) {
+ if (xlo->xlo_state != Xlo_bound)
+ goto out_unlock;
+ xlo->xlo_state = Xlo_rundown;
+ mutex_unlock(&xloop_ctl_mutex);
+ /*
+ * In autoclear mode, stop the xloop thread
+ * and remove configuration after last close.
+ */
+ __xloop_clr_fd(xlo, true);
+ return;
+ } else if (xlo->xlo_state == Xlo_bound) {
+ /*
+ * Otherwise keep thread (if running) and config,
+ * but flush possible ongoing bios in thread.
+ */
+ blk_mq_freeze_queue(xlo->xlo_queue);
+ blk_mq_unfreeze_queue(xlo->xlo_queue);
+ }
+
+out_unlock:
+ mutex_unlock(&xloop_ctl_mutex);
+}
+
+static const struct block_device_operations xlo_fops = {
+ .owner = THIS_MODULE,
+ .open = xlo_open,
+ .release = xlo_release,
+ .ioctl = xlo_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = xlo_compat_ioctl,
+#endif
+};
+
+/*
+ * And now the modules code and kernel interface.
+ */
+static int max_xloop;
+module_param(max_xloop, int, 0444);
+MODULE_PARM_DESC(max_xloop, "Maximum number of xloop devices");
+module_param(max_part, int, 0444);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per xloop device");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manuel Bentele <development@manuel-bentele.de>");
+MODULE_VERSION(__stringify(VERSION));
+MODULE_ALIAS_BLOCKDEV_MAJOR(XLOOP_MAJOR);
+
+int xloop_register_transfer(struct xloop_func_table *funcs)
+{
+ unsigned int n = funcs->number;
+
+ if (n >= MAX_XLO_CRYPT || xfer_funcs[n])
+ return -EINVAL;
+ xfer_funcs[n] = funcs;
+ return 0;
+}
+
+static int unregister_transfer_cb(int id, void *ptr, void *data)
+{
+ struct xloop_device *xlo = ptr;
+ struct xloop_func_table *xfer = data;
+
+ mutex_lock(&xloop_ctl_mutex);
+ if (xlo->xlo_encryption == xfer)
+ xloop_release_xfer(xlo);
+ mutex_unlock(&xloop_ctl_mutex);
+ return 0;
+}
+
+int xloop_unregister_transfer(int number)
+{
+ unsigned int n = number;
+ struct xloop_func_table *xfer;
+
+ if (n == 0 || n >= MAX_XLO_CRYPT || (xfer = xfer_funcs[n]) == NULL)
+ return -EINVAL;
+
+ xfer_funcs[n] = NULL;
+ idr_for_each(&xloop_index_idr, &unregister_transfer_cb, xfer);
+ return 0;
+}
+
+EXPORT_SYMBOL(xloop_register_transfer);
+EXPORT_SYMBOL(xloop_unregister_transfer);
+
+static blk_status_t xloop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
+{
+ struct request *rq = bd->rq;
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ struct xloop_device *xlo = rq->q->queuedata;
+
+ blk_mq_start_request(rq);
+
+ if (xlo->xlo_state != Xlo_bound)
+ return BLK_STS_IOERR;
+
+ switch (req_op(rq)) {
+ case REQ_OP_FLUSH:
+ case REQ_OP_DISCARD:
+ case REQ_OP_WRITE_ZEROES:
+ cmd->use_aio = false;
+ break;
+ default:
+ cmd->use_aio = xlo->use_dio;
+ break;
+ }
+
+ /* always use the first bio's css */
+#ifdef CONFIG_BLK_CGROUP
+ if (cmd->use_aio && rq->bio && rq->bio->bi_blkg) {
+ cmd->css = &bio_blkcg(rq->bio)->css;
+ css_get(cmd->css);
+ } else
+#endif
+ cmd->css = NULL;
+ kthread_queue_work(&xlo->worker, &cmd->work);
+
+ return BLK_STS_OK;
+}
+
+static void xloop_handle_cmd(struct xloop_cmd *cmd)
+{
+ struct request *rq = blk_mq_rq_from_pdu(cmd);
+ const bool write = op_is_write(req_op(rq));
+ struct xloop_device *xlo = rq->q->queuedata;
+ int ret = 0;
+
+ if (write && (xlo->xlo_flags & XLO_FLAGS_READ_ONLY)) {
+ ret = -EIO;
+ goto failed;
+ }
+
+ ret = do_req_filebacked(xlo, rq);
+ failed:
+ /* complete non-aio request */
+ if (!cmd->use_aio || ret) {
+ if (ret == -EOPNOTSUPP)
+ cmd->ret = ret;
+ else
+ cmd->ret = ret ? -EIO : 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
+ if (likely(!blk_should_fake_timeout(rq->q)))
+ blk_mq_complete_request(rq);
+#else
+ blk_mq_complete_request(rq);
+#endif
+ }
+}
+
+static void xloop_queue_work(struct kthread_work *work)
+{
+ struct xloop_cmd *cmd =
+ container_of(work, struct xloop_cmd, work);
+
+ xloop_handle_cmd(cmd);
+}
+
+static int xloop_init_request(struct blk_mq_tag_set *set, struct request *rq,
+ unsigned int hctx_idx, unsigned int numa_node)
+{
+ struct xloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
+ kthread_init_work(&cmd->work, xloop_queue_work);
+ return 0;
+}
+
+static const struct blk_mq_ops xloop_mq_ops = {
+ .queue_rq = xloop_queue_rq,
+ .init_request = xloop_init_request,
+ .complete = xlo_complete_rq,
+};
+
+static struct dentry *xloop_dbgfs_dir;
+
+static int xloop_add(struct xloop_device **l, int i)
+{
+ struct xloop_device *xlo;
+ struct gendisk *disk;
+ int err;
+
+ err = -ENOMEM;
+ xlo = kzalloc(sizeof(*xlo), GFP_KERNEL);
+ if (!xlo)
+ goto out;
+
+ xlo->xlo_state = Xlo_unbound;
+
+ /* allocate id, if @id >= 0, we're requesting that specific id */
+ if (i >= 0) {
+ err = idr_alloc(&xloop_index_idr, xlo, i, i + 1, GFP_KERNEL);
+ if (err == -ENOSPC)
+ err = -EEXIST;
+ } else {
+ err = idr_alloc(&xloop_index_idr, xlo, 0, 0, GFP_KERNEL);
+ }
+ if (err < 0)
+ goto out_free_dev;
+ i = err;
+
+ err = -ENOMEM;
+ xlo->tag_set.ops = &xloop_mq_ops;
+ xlo->tag_set.nr_hw_queues = 1;
+ xlo->tag_set.queue_depth = 128;
+ xlo->tag_set.numa_node = NUMA_NO_NODE;
+ xlo->tag_set.cmd_size = sizeof(struct xloop_cmd);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
+ xlo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_STACKING;
+#else
+ xlo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+#endif
+ xlo->tag_set.driver_data = xlo;
+
+ err = blk_mq_alloc_tag_set(&xlo->tag_set);
+ if (err)
+ goto out_free_idr;
+
+ xlo->xlo_queue = blk_mq_init_queue(&xlo->tag_set);
+ if (IS_ERR(xlo->xlo_queue)) {
+ err = PTR_ERR(xlo->xlo_queue);
+ goto out_cleanup_tags;
+ }
+ xlo->xlo_queue->queuedata = xlo;
+
+ blk_queue_max_hw_sectors(xlo->xlo_queue, BLK_DEF_MAX_SECTORS);
+
+ /*
+ * By default, we do buffer IO, so it doesn't make sense to enable
+ * merge because the I/O submitted to backing file is handled page by
+ * page. For directio mode, merge does help to dispatch bigger request
+ * to underlayer disk. We will enable merge once directio is enabled.
+ */
+ blk_queue_flag_set(QUEUE_FLAG_NOMERGES, xlo->xlo_queue);
+
+ err = -ENOMEM;
+ xlo->xlo_fmt = xloop_file_fmt_alloc();
+ if (!xlo->xlo_fmt)
+ goto out_free_queue;
+
+ xloop_file_fmt_set_xlo(xlo->xlo_fmt, xlo);
+
+ err = -ENOMEM;
+ disk = xlo->xlo_disk = alloc_disk(1 << part_shift);
+ if (!disk)
+ goto out_free_file_fmt;
+
+ /*
+ * Disable partition scanning by default. The in-kernel partition
+ * scanning can be requested individually per-device during its
+ * setup. Userspace can always add and remove partitions from all
+ * devices. The needed partition minors are allocated from the
+ * extended minor space, the main xloop device numbers will continue
+ * to match the xloop minors, regardless of the number of partitions
+ * used.
+ *
+ * If max_part is given, partition scanning is globally enabled for
+ * all xloop devices. The minors for the main xloop devices will be
+ * multiples of max_part.
+ *
+ * Note: Global-for-all-devices, set-only-at-init, read-only module
+ * parameteters like 'max_xloop' and 'max_part' make things needlessly
+ * complicated, are too static, inflexible and may surprise
+ * userspace tools. Parameters like this in general should be avoided.
+ */
+ if (!part_shift)
+ disk->flags |= GENHD_FL_NO_PART_SCAN;
+ disk->flags |= GENHD_FL_EXT_DEVT;
+ atomic_set(&xlo->xlo_refcnt, 0);
+ xlo->xlo_number = i;
+ spin_lock_init(&xlo->xlo_lock);
+ disk->major = XLOOP_MAJOR;
+ disk->first_minor = i << part_shift;
+ disk->fops = &xlo_fops;
+ disk->private_data = xlo;
+ disk->queue = xlo->xlo_queue;
+ sprintf(disk->disk_name, "xloop%d", i);
+ add_disk(disk);
+ *l = xlo;
+
+ /* initialize debugfs entries */
+ /* create for each loop device a debugfs directory under 'loop' if
+ * the 'block' directory exists, otherwise create the loop directory in
+ * the root directory */
+#ifdef CONFIG_DEBUG_FS
+ xlo->xlo_dbgfs_dir = debugfs_create_dir(disk->disk_name, xloop_dbgfs_dir);
+
+ if (IS_ERR_OR_NULL(xlo->xlo_dbgfs_dir)) {
+ err = -ENODEV;
+ xlo->xlo_dbgfs_dir = NULL;
+ goto out_free_file_fmt;
+ }
+#endif
+
+ return xlo->xlo_number;
+
+out_free_file_fmt:
+ xloop_file_fmt_free(xlo->xlo_fmt);
+out_free_queue:
+ blk_cleanup_queue(xlo->xlo_queue);
+out_cleanup_tags:
+ blk_mq_free_tag_set(&xlo->tag_set);
+out_free_idr:
+ idr_remove(&xloop_index_idr, i);
+out_free_dev:
+ kfree(xlo);
+out:
+ return err;
+}
+
+static void xloop_remove(struct xloop_device *xlo)
+{
+ xloop_file_fmt_free(xlo->xlo_fmt);
+ debugfs_remove(xlo->xlo_dbgfs_dir);
+ del_gendisk(xlo->xlo_disk);
+ blk_cleanup_queue(xlo->xlo_queue);
+ blk_mq_free_tag_set(&xlo->tag_set);
+ put_disk(xlo->xlo_disk);
+ kfree(xlo);
+}
+
+static int find_free_cb(int id, void *ptr, void *data)
+{
+ struct xloop_device *xlo = ptr;
+ struct xloop_device **l = data;
+
+ if (xlo->xlo_state == Xlo_unbound) {
+ *l = xlo;
+ return 1;
+ }
+ return 0;
+}
+
+static int xloop_lookup(struct xloop_device **l, int i)
+{
+ struct xloop_device *xlo;
+ int ret = -ENODEV;
+
+ if (i < 0) {
+ int err;
+
+ err = idr_for_each(&xloop_index_idr, &find_free_cb, &xlo);
+ if (err == 1) {
+ *l = xlo;
+ ret = xlo->xlo_number;
+ }
+ goto out;
+ }
+
+ /* lookup and return a specific i */
+ xlo = idr_find(&xloop_index_idr, i);
+ if (xlo) {
+ *l = xlo;
+ ret = xlo->xlo_number;
+ }
+out:
+ return ret;
+}
+
+static struct kobject *xloop_probe(dev_t dev, int *part, void *data)
+{
+ struct xloop_device *xlo;
+ struct kobject *kobj;
+ int err;
+
+ mutex_lock(&xloop_ctl_mutex);
+ err = xloop_lookup(&xlo, MINOR(dev) >> part_shift);
+ if (err < 0)
+ err = xloop_add(&xlo, MINOR(dev) >> part_shift);
+ if (err < 0)
+ kobj = NULL;
+ else
+ kobj = get_disk_and_module(xlo->xlo_disk);
+ mutex_unlock(&xloop_ctl_mutex);
+
+ *part = 0;
+ return kobj;
+}
+
+static long xloop_control_ioctl(struct file *file, unsigned int cmd,
+ unsigned long parm)
+{
+ struct xloop_device *xlo;
+ int ret;
+
+ ret = mutex_lock_killable(&xloop_ctl_mutex);
+ if (ret)
+ return ret;
+
+ ret = -ENOSYS;
+ switch (cmd) {
+ case XLOOP_CTL_ADD:
+ ret = xloop_lookup(&xlo, parm);
+ if (ret >= 0) {
+ ret = -EEXIST;
+ break;
+ }
+ ret = xloop_add(&xlo, parm);
+ break;
+ case XLOOP_CTL_REMOVE:
+ ret = xloop_lookup(&xlo, parm);
+ if (ret < 0)
+ break;
+ if (xlo->xlo_state != Xlo_unbound) {
+ ret = -EBUSY;
+ break;
+ }
+ if (atomic_read(&xlo->xlo_refcnt) > 0) {
+ ret = -EBUSY;
+ break;
+ }
+ xlo->xlo_disk->private_data = NULL;
+ idr_remove(&xloop_index_idr, xlo->xlo_number);
+ xloop_remove(xlo);
+ break;
+ case XLOOP_CTL_GET_FREE:
+ ret = xloop_lookup(&xlo, -1);
+ if (ret >= 0)
+ break;
+ ret = xloop_add(&xlo, -1);
+ }
+ mutex_unlock(&xloop_ctl_mutex);
+
+ return ret;
+}
+
+static const struct file_operations xloop_ctl_fops = {
+ .open = nonseekable_open,
+ .unlocked_ioctl = xloop_control_ioctl,
+ .compat_ioctl = xloop_control_ioctl,
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice xloop_misc = {
+ .minor = XLOOP_CTRL_MINOR,
+ .name = "xloop-control",
+ .fops = &xloop_ctl_fops,
+};
+
+MODULE_ALIAS_MISCDEV(XLOOP_CTRL_MINOR);
+MODULE_ALIAS("devname:xloop-control");
+
+static int __init xloop_init(void)
+{
+ int i, nr;
+ unsigned long range;
+ struct xloop_device *xlo;
+ int err;
+
+ part_shift = 0;
+ if (max_part > 0) {
+ part_shift = fls(max_part);
+
+ /*
+ * Adjust max_part according to part_shift as it is exported
+ * to user space so that user can decide correct minor number
+ * if [s]he want to create more devices.
+ *
+ * Note that -1 is required because partition 0 is reserved
+ * for the whole disk.
+ */
+ max_part = (1UL << part_shift) - 1;
+ }
+
+ if ((1UL << part_shift) > DISK_MAX_PARTS) {
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ if (max_xloop > 1UL << (MINORBITS - part_shift)) {
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ /*
+ * If max_xloop is specified, create that many devices upfront.
+ * This also becomes a hard limit. If max_xloop is not specified,
+ * create CONFIG_BLK_DEV_XLOOP_MIN_COUNT xloop devices at module
+ * init time. xloop devices can be requested on-demand with the
+ * /dev/xloop-control interface, or be instantiated by accessing
+ * a 'dead' device node.
+ */
+ if (max_xloop) {
+ nr = CONFIG_BLK_DEV_XLOOP_MIN_COUNT;
+ range = 1UL << MINORBITS;
+ }
+
+ err = misc_register(&xloop_misc);
+ if (err < 0)
+ goto err_out;
+
+
+ if (register_blkdev(XLOOP_MAJOR, "xloop")) {
+ err = -EIO;
+ goto misc_out;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ xloop_dbgfs_dir = debugfs_create_dir("xloop", NULL);
+ if (IS_ERR_OR_NULL(xloop_dbgfs_dir)) {
+ err = -ENODEV;
+ goto misc_out;
+ }
+#endif
+
+ blk_register_region(MKDEV(XLOOP_MAJOR, 0), range,
+ THIS_MODULE, xloop_probe, NULL, NULL);
+
+ /* pre-create number of devices given by config or max_xloop */
+ mutex_lock(&xloop_ctl_mutex);
+ for (i = 0; i < nr; i++)
+ xloop_add(&xlo, i);
+ mutex_unlock(&xloop_ctl_mutex);
+
+ pr_info("module in version %s loaded\n", __stringify(VERSION));
+ return 0;
+
+misc_out:
+ misc_deregister(&xloop_misc);
+err_out:
+ return err;
+}
+
+static int xloop_exit_cb(int id, void *ptr, void *data)
+{
+ struct xloop_device *xlo = ptr;
+
+ xloop_remove(xlo);
+ return 0;
+}
+
+static void __exit xloop_exit(void)
+{
+ unsigned long range;
+
+ range = max_xloop ? max_xloop << part_shift : 1UL << MINORBITS;
+
+ mutex_lock(&xloop_ctl_mutex);
+
+ idr_for_each(&xloop_index_idr, &xloop_exit_cb, NULL);
+ idr_destroy(&xloop_index_idr);
+
+ blk_unregister_region(MKDEV(XLOOP_MAJOR, 0), range);
+ unregister_blkdev(XLOOP_MAJOR, "xloop");
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(xloop_dbgfs_dir);
+#endif
+
+ misc_deregister(&xloop_misc);
+
+ mutex_unlock(&xloop_ctl_mutex);
+
+ pr_info("exit module\n");
+}
+
+module_init(xloop_init);
+module_exit(xloop_exit);
+
+#ifndef MODULE
+static int __init max_xloop_setup(char *str)
+{
+ max_xloop = simple_strtol(str, NULL, 0);
+ return 1;
+}
+
+__setup("max_xloop=", max_xloop_setup);
+#endif
diff --git a/src/kernel/xloop_main.h b/src/kernel/xloop_main.h
new file mode 100644
index 0000000..e1b4cb6
--- /dev/null
+++ b/src/kernel/xloop_main.h
@@ -0,0 +1,107 @@
+/*
+ * loop_main.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
+ * permitted under the GNU General Public License.
+ */
+#ifndef _LINUX_XLOOP_H
+#define _LINUX_XLOOP_H
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include "uapi_xloop.h"
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#include "xloop_file_fmt.h"
+
+/* Possible states of device */
+enum {
+ Xlo_unbound,
+ Xlo_bound,
+ Xlo_rundown,
+};
+
+struct xloop_func_table;
+
+struct xloop_device {
+ int xlo_number;
+ atomic_t xlo_refcnt;
+ loff_t xlo_offset;
+ loff_t xlo_sizelimit;
+ int xlo_flags;
+ int (*transfer)(struct xloop_device *, int cmd,
+ struct page *raw_page, unsigned raw_off,
+ struct page *xloop_page, unsigned xloop_off,
+ int size, sector_t real_block);
+ char xlo_file_name[XLO_NAME_SIZE];
+ char xlo_crypt_name[XLO_NAME_SIZE];
+ char xlo_encrypt_key[XLO_KEY_SIZE];
+ int xlo_encrypt_key_size;
+ struct xloop_func_table *xlo_encryption;
+ __u32 xlo_init[2];
+ kuid_t xlo_key_owner; /* Who set the key */
+ int (*ioctl)(struct xloop_device *, int cmd,
+ unsigned long arg);
+
+ struct xloop_file_fmt *xlo_fmt;
+
+ struct file * xlo_backing_file;
+ struct block_device *xlo_device;
+ void *key_data;
+
+ gfp_t old_gfp_mask;
+
+ spinlock_t xlo_lock;
+ int xlo_state;
+ struct kthread_worker worker;
+ struct task_struct *worker_task;
+ bool use_dio;
+ bool sysfs_inited;
+
+ struct request_queue *xlo_queue;
+ struct blk_mq_tag_set tag_set;
+ struct gendisk *xlo_disk;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *xlo_dbgfs_dir;
+#endif
+};
+
+struct xloop_cmd {
+ struct kthread_work work;
+ bool use_aio; /* use AIO interface to handle I/O */
+ atomic_t ref; /* only for aio */
+ long ret;
+ struct kiocb iocb;
+ struct bio_vec *bvec;
+ struct cgroup_subsys_state *css;
+};
+
+/* Support for loadable transfer modules */
+struct xloop_func_table {
+ int number; /* filter type */
+ int (*transfer)(struct xloop_device *xlo, int cmd,
+ struct page *raw_page, unsigned raw_off,
+ struct page *xloop_page, unsigned xloop_off,
+ int size, sector_t real_block);
+ int (*init)(struct xloop_device *, const struct xloop_info64 *);
+ /* release is called from xloop_unregister_transfer or clr_fd */
+ int (*release)(struct xloop_device *);
+ int (*ioctl)(struct xloop_device *, int cmd, unsigned long arg);
+ struct module *owner;
+};
+
+extern inline struct device *xloop_device_to_dev(struct xloop_device *xlo);
+
+int xloop_register_transfer(struct xloop_func_table *funcs);
+int xloop_unregister_transfer(int number);
+
+#endif
diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt
new file mode 100644
index 0000000..cfc5548
--- /dev/null
+++ b/src/utils/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-utils)
+
+# include global headers
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+# prepare date for configuring config.h
+string(TIMESTAMP DATE "%d-%b-%Y")
+
+# configure configuration config.h and add it to each source file
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+add_compile_options(-include ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+# add xloop specific compile options
+add_definitions(-DCONFIG_BLK_DEV_XLOOP_MIN_COUNT=${BLK_DEV_XLOOP_MIN_COUNT} -DXLOOP_MAJOR=${XLOOP_MAJOR})
+
+add_subdirectory(lib)
+add_subdirectory(libsmartcols)
+add_subdirectory(sys-utils)
+
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bash-completion/xlosetup
+ DESTINATION share/bash-completion/completions
+ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
+ COMPONENT main)
diff --git a/src/utils/bash-completion/xlosetup b/src/utils/bash-completion/xlosetup
new file mode 100644
index 0000000..cdf75f1
--- /dev/null
+++ b/src/utils/bash-completion/xlosetup
@@ -0,0 +1,85 @@
+_xlosetup_module()
+{
+ local cur prev OPTS ARG
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ case $prev in
+ '-d'|'--detach')
+ ARG="$($1 --output NAME | awk '{if (1 < NR) {print}}')"
+ COMPREPLY=( $(compgen -W "$ARG" -- $cur) )
+ return 0
+ ;;
+ '-j'|'--associated')
+ ARG="$($1 --output BACK-FILE | awk '{if (1 < NR) {print}}')"
+ COMPREPLY=( $(compgen -W "$ARG" -- $cur) )
+ return 0
+ ;;
+ '-c'|'--set-capacity')
+ ARG="$(for I in /dev/xloop[0-9]*; do if [ -e $I ]; then echo $I; fi; done)"
+ COMPREPLY=( $(compgen -W "$ARG" -- $cur) )
+ return 0
+ ;;
+ '-o'|'--offset'|'--sizelimit')
+ COMPREPLY=( $(compgen -W "number" -- $cur) )
+ return 0
+ ;;
+ '-t'|'--type')
+ ARG="RAW QCOW VDI VMDK"
+ COMPREPLY=( $(compgen -W "$ARG" -- $cur) )
+ return 0
+ ;;
+ '-O'|'--output')
+ local prefix realcur OUTPUT_ALL OUTPUT
+ realcur="${cur##*,}"
+ prefix="${cur%$realcur}"
+ OUTPUT_ALL="NAME AUTOCLEAR BACK-FILE BACK-INO
+ BACK-MAJ:MIN FILE-FORMAT MAJ:MIN OFFSET PARTSCAN RO
+ SIZELIMIT DIO"
+ for WORD in $OUTPUT_ALL; do
+ if ! [[ $prefix == *"$WORD"* ]]; then
+ OUTPUT="$WORD ${OUTPUT:-""}"
+ fi
+ done
+ compopt -o nospace
+ COMPREPLY=( $(compgen -P "$prefix" -W "$OUTPUT" -S ',' -- $realcur) )
+ return 0
+ ;;
+ '-h'|'--help'|'-V'|'--version')
+ return 0
+ ;;
+ esac
+ case $cur in
+ -*)
+ OPTS="--all
+ --detach
+ --detach-all
+ --find
+ --set-capacity
+ --associated
+ --nooverlap
+ --offset
+ --sizelimit
+ --partscan
+ --read-only
+ --show
+ --type
+ --verbose
+ --json
+ --list
+ --noheadings
+ --output
+ --output-all
+ --raw
+ --help
+ --version"
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
+ return 0
+ ;;
+ esac
+ local IFS=$'\n'
+ compopt -o filenames
+ COMPREPLY=( $(compgen -f -- $cur) )
+ return 0
+}
+complete -F _xlosetup_module xlosetup
diff --git a/src/utils/config.h.in b/src/utils/config.h.in
new file mode 100644
index 0000000..40b8d34
--- /dev/null
+++ b/src/utils/config.h.in
@@ -0,0 +1,897 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Enable agetty --reload feature */
+#define AGETTY_RELOAD 1
+
+/* Should chfn and chsh require the user to enter the password? */
+#define CHFN_CHSH_PASSWORD 1
+
+/* Path to hwclock adjtime file */
+#define CONFIG_ADJTIME_PATH "/etc/adjtime"
+
+/* Define if cryptsetup is to be loaded via dlopen */
+/* #undef CRYPTSETUP_VIA_DLOPEN */
+
+/* Define to 1 if translation of program messages to the user's native
+ language is requested. */
+#define ENABLE_NLS 1
+
+/* search path for fs helpers */
+#define FS_SEARCH_PATH "/sbin:/sbin/fs.d:/sbin/fs"
+
+/* Define to 1 if you have the <asm/io.h> header file. */
+/* #undef HAVE_ASM_IO_H */
+
+/* Define if btrfs stuff is available */
+#define HAVE_BTRFS_SUPPORT 1
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+#define HAVE_BYTESWAP_H 1
+
+/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the
+ CoreFoundation framework. */
+/* #undef HAVE_CFLOCALECOPYCURRENT */
+
+/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in
+ the CoreFoundation framework. */
+/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
+
+/* Define to 1 if you have the `clearenv' function. */
+#define HAVE_CLEARENV 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if the system has the type `cpu_set_t'. */
+#define HAVE_CPU_SET_T 1
+
+/* Define if cryptsetup is available */
+/* #undef HAVE_CRYPTSETUP */
+
+/* Define if crypt_activate_by_signed_key exist in -lcryptsetup */
+/* #undef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY */
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#define HAVE_CRYPT_H 1
+
+/* Define if the GNU dcgettext() function is already present or preinstalled.
+ */
+#define HAVE_DCGETTEXT 1
+
+/* Define to 1 if you have the declaration of `BLK_ZONE_REP_CAPACITY', and to
+ 0 if you don't. */
+#define HAVE_DECL_BLK_ZONE_REP_CAPACITY 0
+
+/* Define to 1 if you have the declaration of `CPU_ALLOC', and to 0 if you
+ don't. */
+#define HAVE_DECL_CPU_ALLOC 1
+
+/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't.
+ */
+/* #undef HAVE_DECL_DIRFD */
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+/* #undef HAVE_DECL_TZNAME */
+
+/* Define to 1 if you have the declaration of `_NL_TIME_WEEK_1STDAY', and to 0
+ if you don't. */
+#define HAVE_DECL__NL_TIME_WEEK_1STDAY 1
+
+/* Define to 1 if you have the `dirfd' function. */
+#define HAVE_DIRFD 1
+
+/* Define to 1 if `dd_fd' is a member of `DIR'. */
+/* #undef HAVE_DIR_DD_FD */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `eaccess' function. */
+#define HAVE_EACCESS 1
+
+/* Define to 1 if you have the <endian.h> header file. */
+#define HAVE_ENDIAN_H 1
+
+/* Define to 1 if have **environ prototype */
+#define HAVE_ENVIRON_DECL 1
+
+/* Define to 1 if you have the `err' function. */
+#define HAVE_ERR 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `errx' function. */
+#define HAVE_ERRX 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the `explicit_bzero' function. */
+#define HAVE_EXPLICIT_BZERO 1
+
+/* Have valid fallocate() function */
+#define HAVE_FALLOCATE 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fpurge' function. */
+/* #undef HAVE_FPURGE */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `fstatat' function. */
+#define HAVE_FSTATAT 1
+
+/* Define to 1 if you have the `fsync' function. */
+#define HAVE_FSYNC 1
+
+/* Define to 1 if you have the `futimens' function. */
+#define HAVE_FUTIMENS 1
+
+/* Define to 1 if you have the `getdomainname' function. */
+#define HAVE_GETDOMAINNAME 1
+
+/* Define to 1 if you have the `getdtablesize' function. */
+#define HAVE_GETDTABLESIZE 1
+
+/* Define to 1 if you have the `getexecname' function. */
+/* #undef HAVE_GETEXECNAME */
+
+/* Define to 1 if you have the `getmntinfo' function. */
+/* #undef HAVE_GETMNTINFO */
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getrandom' function. */
+#define HAVE_GETRANDOM 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the `getsgnam' function. */
+#define HAVE_GETSGNAM 1
+
+/* Define if the GNU gettext() function is already present or preinstalled. */
+#define HAVE_GETTEXT 1
+
+/* Define to 1 if you have the `getusershell' function. */
+#define HAVE_GETUSERSHELL 1
+
+/* Define if you have the iconv() function and it works. */
+/* #undef HAVE_ICONV */
+
+/* Define to 1 if you have the `inotify_init' function. */
+#define HAVE_INOTIFY_INIT 1
+
+/* Define to 1 if you have the `inotify_init1' function. */
+#define HAVE_INOTIFY_INIT1 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `ioperm' function. */
+#define HAVE_IOPERM 1
+
+/* Define to 1 if you have the `iopl' function. */
+#define HAVE_IOPL 1
+
+/* Define to 1 if you have the `isnan' function. */
+#define HAVE_ISNAN 1
+
+/* Define to 1 if you have the `jrand48' function. */
+#define HAVE_JRAND48 1
+
+/* Define if langinfo.h defines ALTMON_x constants */
+#define HAVE_LANGINFO_ALTMON 1
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define if langinfo.h defines _NL_ABALTMON_x constants */
+#define HAVE_LANGINFO_NL_ABALTMON 1
+
+/* Define to 1 if you have the <lastlog.h> header file. */
+#define HAVE_LASTLOG_H 1
+
+/* Define to 1 if you have the `lchown' function. */
+#define HAVE_LCHOWN 1
+
+/* Define to 1 if you have the `audit' library (-laudit). */
+/* #undef HAVE_LIBAUDIT */
+
+/* Define to 1 if you have the -lblkid. */
+#define HAVE_LIBBLKID 1
+
+/* Define to 1 if you have the `cap-ng' library (-lcap-ng). */
+#define HAVE_LIBCAP_NG 1
+
+/* Do we need -lcrypt? */
+#define HAVE_LIBCRYPT 1
+
+/* Define if libeconf is available */
+/* #undef HAVE_LIBECONF */
+
+/* Define if libmount available. */
+#define HAVE_LIBMOUNT 1
+
+/* Define if ncurses library available */
+/* #undef HAVE_LIBNCURSES */
+
+/* Define if ncursesw library available */
+#define HAVE_LIBNCURSESW 1
+
+/* Define to 1 if you have the `readline' library (-lreadline). */
+#define HAVE_LIBREADLINE 1
+
+/* Define if librtas exists */
+/* #undef HAVE_LIBRTAS */
+
+/* Define if SELinux is available */
+/* #undef HAVE_LIBSELINUX */
+
+/* Define if libsystemd is available */
+#define HAVE_LIBSYSTEMD 1
+
+/* Define if libtinfo or libtinfow available. */
+#define HAVE_LIBTINFO 1
+
+/* Define to 1 if you have the `udev' library (-ludev). */
+#define HAVE_LIBUDEV 1
+
+/* Define if libuser is available */
+/* #undef HAVE_LIBUSER */
+
+/* Define to 1 if you have the `utempter' library (-lutempter). */
+/* #undef HAVE_LIBUTEMPTER */
+
+/* Define to 1 if you have the `util' library (-lutil). */
+#define HAVE_LIBUTIL 1
+
+/* Define to 1 if you have the <libutil.h> header file. */
+/* #undef HAVE_LIBUTIL_H */
+
+/* Define to 1 if you have the -luuid. */
+#define HAVE_LIBUUID 1
+
+/* Define to 1 if you have the <linux/blkpg.h> header file. */
+#define HAVE_LINUX_BLKPG_H 1
+
+/* Define to 1 if you have the <linux/blkzoned.h> header file. */
+#define HAVE_LINUX_BLKZONED_H 1
+
+/* Define to 1 if you have the <linux/btrfs.h> header file. */
+#define HAVE_LINUX_BTRFS_H 1
+
+/* Define to 1 if you have the <linux/capability.h> header file. */
+#define HAVE_LINUX_CAPABILITY_H 1
+
+/* Define to 1 if you have the <linux/cdrom.h> header file. */
+#define HAVE_LINUX_CDROM_H 1
+
+/* Define to 1 if you have the <linux/compiler.h> header file. */
+/* #undef HAVE_LINUX_COMPILER_H */
+
+/* Define to 1 if you have the <linux/falloc.h> header file. */
+#define HAVE_LINUX_FALLOC_H 1
+
+/* Define to 1 if you have the <linux/fd.h> header file. */
+#define HAVE_LINUX_FD_H 1
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+/* #undef HAVE_LINUX_FS_H */
+
+/* Define to 1 if you have the <linux/gsmmux.h> header file. */
+#define HAVE_LINUX_GSMMUX_H 1
+
+/* Define to 1 if you have the <linux/major.h> header file. */
+#define HAVE_LINUX_MAJOR_H 1
+
+/* Define to 1 if you have the <linux/net_namespace.h> header file. */
+#define HAVE_LINUX_NET_NAMESPACE_H 1
+
+/* Define to 1 if you have the <linux/raw.h> header file. */
+#define HAVE_LINUX_RAW_H 1
+
+/* Define to 1 if you have the <linux/securebits.h> header file. */
+#define HAVE_LINUX_SECUREBITS_H 1
+
+/* Define to 1 if you have the <linux/tiocl.h> header file. */
+#define HAVE_LINUX_TIOCL_H 1
+
+/* Define to 1 if you have the <linux/version.h> header file. */
+#define HAVE_LINUX_VERSION_H 1
+
+/* Define to 1 if you have the <linux/watchdog.h> header file. */
+#define HAVE_LINUX_WATCHDOG_H 1
+
+/* Define to 1 if you have the `llseek' function. */
+/* #undef HAVE_LLSEEK */
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if the system has the type `loff_t'. */
+#define HAVE_LOFF_T 1
+
+/* Define to 1 if you have the libmagic present. */
+#define HAVE_MAGIC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+#define HAVE_MEMPCPY 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#define HAVE_MKOSTEMP 1
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#define HAVE_MNTENT_H 1
+
+/* Define to 1 if you have the `nanosleep' function. */
+#define HAVE_NANOSLEEP 1
+
+/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
+/* #undef HAVE_NCURSESW_NCURSES_H */
+
+/* Define to 1 if you have the <ncursesw/term.h> header file. */
+/* #undef HAVE_NCURSESW_TERM_H */
+
+/* Define to 1 if you have the <ncurses.h> header file. */
+#define HAVE_NCURSES_H 1
+
+/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
+/* #undef HAVE_NCURSES_NCURSES_H */
+
+/* Define to 1 if you have the <ncurses/term.h> header file. */
+/* #undef HAVE_NCURSES_TERM_H */
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+/* #undef HAVE_NET_IF_DL_H */
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have the `ntp_gettime' function. */
+#define HAVE_NTP_GETTIME 1
+
+/* Define to 1 if you have the `openat' function. */
+#define HAVE_OPENAT 1
+
+/* Define to 1 if you have the `open_memstream' function. */
+#define HAVE_OPEN_MEMSTREAM 1
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Define if libpcre2 is available */
+#define HAVE_PCRE 1
+
+/* Define to 1 if you have the `personality' function. */
+#define HAVE_PERSONALITY 1
+
+/* Define to 1 if you have the `pidfd_open' function. */
+/* #undef HAVE_PIDFD_OPEN */
+
+/* Define to 1 if you have the `pidfd_send_signal' function. */
+/* #undef HAVE_PIDFD_SEND_SIGNAL */
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+#define HAVE_POSIX_FADVISE 1
+
+/* Have valid posix_fallocate() function */
+#define HAVE_POSIX_FALLOCATE 1
+
+/* Define to 1 if you have the `prctl' function. */
+#define HAVE_PRCTL 1
+
+/* Define to 1 if you have the `prlimit' function. */
+#define HAVE_PRLIMIT 1
+
+/* Define if program_invocation_short_name is defined */
+#define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1
+
+/* have PTY support */
+#define HAVE_PTY 1
+
+/* Define to 1 if you have the <pty.h> header file. */
+#define HAVE_PTY_H 1
+
+/* Define to 1 if you have the `qsort_r' function. */
+#define HAVE_QSORT_R 1
+
+/* Define to 1 if you have the `reboot' function. */
+#define HAVE_REBOOT 1
+
+/* Define if curses library has the resizeterm(). */
+#define HAVE_RESIZETERM 1
+
+/* Define to 1 if you have the `rpmatch' function. */
+#define HAVE_RPMATCH 1
+
+/* Define if struct sockaddr contains sa_len */
+/* #undef HAVE_SA_LEN */
+
+/* Define to 1 if you have the `scandirat' function. */
+#define HAVE_SCANDIRAT 1
+
+/* Define to 1 if you have the `sched_setattr' function. */
+/* #undef HAVE_SCHED_SETATTR */
+
+/* Define to 1 if you have the `sched_setscheduler' function. */
+#define HAVE_SCHED_SETSCHEDULER 1
+
+/* Define to 1 if you have the `secure_getenv' function. */
+#define HAVE_SECURE_GETENV 1
+
+/* Define to 1 if you have the `security_get_initial_context' function. */
+/* #undef HAVE_SECURITY_GET_INITIAL_CONTEXT */
+
+/* Define to 1 if you have the <security/openpam.h> header file. */
+/* #undef HAVE_SECURITY_OPENPAM_H */
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the <security/pam_misc.h> header file. */
+#define HAVE_SECURITY_PAM_MISC_H 1
+
+/* Define to 1 if you have the `setitimer' function. */
+/* #undef HAVE_SETITIMER */
+
+/* Define to 1 if you have the `setns' function. */
+#define HAVE_SETNS 1
+
+/* Define to 1 if you have the `setprogname' function. */
+/* #undef HAVE_SETPROGNAME */
+
+/* Define to 1 if you have the `setresgid' function. */
+#define HAVE_SETRESGID 1
+
+/* Define to 1 if you have the `setresuid' function. */
+#define HAVE_SETRESUID 1
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#define HAVE_SHADOW_H 1
+
+/* Define to 1 if the system has the type `sighandler_t'. */
+#define HAVE_SIGHANDLER_T 1
+
+/* Define to 1 if you have the `sigqueue' function. */
+#define HAVE_SIGQUEUE 1
+
+/* Define to 1 if you have the <slang.h> header file. */
+/* #undef HAVE_SLANG_H */
+
+/* Define to 1 if you have the <slang/slang.h> header file. */
+/* #undef HAVE_SLANG_SLANG_H */
+
+/* Define to 1 if you have the <slang/slcurses.h> header file. */
+/* #undef HAVE_SLANG_SLCURSES_H */
+
+/* Define to 1 if you have the <slcurses.h> header file. */
+/* #undef HAVE_SLCURSES_H */
+
+/* Add SMACK support */
+/* #undef HAVE_SMACK */
+
+/* Define to 1 if you have the `srandom' function. */
+#define HAVE_SRANDOM 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio_ext.h> header file. */
+#define HAVE_STDIO_EXT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strnchr' function. */
+/* #undef HAVE_STRNCHR */
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if have strsignal function prototype */
+#define HAVE_STRSIGNAL_DECL 1
+
+/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
+
+/* Define to 1 if `c_line' is a member of `struct termios'. */
+#define HAVE_STRUCT_TERMIOS_C_LINE 1
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the `swapoff' function. */
+#define HAVE_SWAPOFF 1
+
+/* Define to 1 if you have the `swapon' function. */
+#define HAVE_SWAPON 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* Define to 1 if you have the `sysinfo' function. */
+#define HAVE_SYSINFO 1
+
+/* Define to 1 if you have the <sys/disklabel.h> header file. */
+/* #undef HAVE_SYS_DISKLABEL_H */
+
+/* Define to 1 if you have the <sys/disk.h> header file. */
+/* #undef HAVE_SYS_DISK_H */
+
+/* Define to 1 if you have the <sys/endian.h> header file. */
+/* #undef HAVE_SYS_ENDIAN_H */
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/ioccom.h> header file. */
+/* #undef HAVE_SYS_IOCCOM_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/io.h> header file. */
+#define HAVE_SYS_IO_H 1
+
+/* Define to 1 if you have the <sys/mkdev.h> header file. */
+/* #undef HAVE_SYS_MKDEV_H */
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#define HAVE_SYS_MOUNT_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#define HAVE_SYS_PRCTL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/signalfd.h> header file. */
+#define HAVE_SYS_SIGNALFD_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/swap.h> header file. */
+#define HAVE_SYS_SWAP_H 1
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H 1
+
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#define HAVE_SYS_SYSMACROS_H 1
+
+/* Define to 1 if you have the <sys/timex.h> header file. */
+#define HAVE_SYS_TIMEX_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/ttydefaults.h> header file. */
+#define HAVE_SYS_TTYDEFAULTS_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <term.h> header file. */
+#define HAVE_TERM_H 1
+
+/* Define to 1 if you have the `timegm' function. */
+#define HAVE_TIMEGM 1
+
+/* Define if timer_create exist in -lrt -lpthread */
+#define HAVE_TIMER_CREATE 1
+
+/* Define to 1 if the target supports thread-local storage. */
+#define HAVE_TLS 1
+
+/* Does struct tm have a field tm_gmtoff? */
+#define HAVE_TM_GMTOFF 1
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#define HAVE_TM_ZONE 1
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if the system has the type `union semun'. */
+/* #undef HAVE_UNION_SEMUN */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unlinkat' function. */
+#define HAVE_UNLINKAT 1
+
+/* Define to 1 if you have the `unshare' function. */
+#define HAVE_UNSHARE 1
+
+/* Define to 1 if you have the `updwtmpx' function. */
+#define HAVE_UPDWTMPX 1
+
+/* Define if curses library has the use_default_colors(). */
+#define HAVE_USE_DEFAULT_COLORS 1
+
+/* Define to 1 if you have the `usleep' function. */
+#define HAVE_USLEEP 1
+
+/* Define to 1 if you have the `utimensat' function. */
+#define HAVE_UTIMENSAT 1
+
+/* Define to 1 if you have the <utmpx.h> header file. */
+#define HAVE_UTMPX_H 1
+
+/* Define to 1 if you have the <utmp.h> header file. */
+#define HAVE_UTMP_H 1
+
+/* Define to 1 if you want to use uuid daemon. */
+#define HAVE_UUIDD 1
+
+/* Define to 1 if you have the `vwarnx' function. */
+#define HAVE_VWARNX 1
+
+/* Define to 1 if you have the `warn' function. */
+#define HAVE_WARN 1
+
+/* Define to 1 if you have the `warnx' function. */
+#define HAVE_WARNX 1
+
+/* Do we have wide character support? */
+#define HAVE_WIDECHAR 1
+
+/* Define to 1 if you have the `__fpending' function. */
+#define HAVE___FPENDING 1
+
+/* Define to 1 if you have the `__fpurge' function. */
+#define HAVE___FPURGE 1
+
+/* Define if __progname is defined */
+#define HAVE___PROGNAME 1
+
+/* Define to 1 if you have the `__secure_getenv' function. */
+/* #undef HAVE___SECURE_GETENV */
+
+/* libblkid date string */
+#define LIBBLKID_DATE "@DATE@"
+
+/* libblkid version string */
+#define LIBBLKID_VERSION "@VERSION@"
+
+/* libfdisk version string */
+#define LIBFDISK_VERSION "@VERSION@"
+
+/* libmount version string */
+#define LIBMOUNT_VERSION "@VERSION@"
+
+/* libsmartcols version string */
+#define LIBSMARTCOLS_VERSION "@VERSION@"
+
+/* Should login chown /dev/vcsN? */
+/* #undef LOGIN_CHOWN_VCS */
+
+/* Should login stat() the mailbox? */
+/* #undef LOGIN_STAT_MAIL */
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* "Multi-arch triplet for whereis library search path" */
+/* #undef MULTIARCHTRIPLET */
+
+/* Define to 1 if assertions should be disabled. */
+/* #undef NDEBUG */
+
+/* Should chsh allow only shells in /etc/shells? */
+#define ONLY_LISTED_SHELLS 1
+
+/* Name of package */
+#define PACKAGE "util-linux"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "kzak@redhat.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "util-linux"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "util-linux @VERSION@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "util-linux"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://www.kernel.org/pub/linux/utils/util-linux/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@VERSION@"
+
+/* Should pg ring the bell on invalid keys? */
+#define PG_BELL 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Fallback syscall number for fallocate */
+/* #undef SYS_fallocate */
+
+/* Fallback syscall number for ioprio_get */
+/* #undef SYS_ioprio_get */
+
+/* Fallback syscall number for ioprio_set */
+/* #undef SYS_ioprio_set */
+
+/* Fallback syscall number for pidfd_open */
+/* #undef SYS_pidfd_open */
+
+/* Fallback syscall number for pidfd_send_signal */
+/* #undef SYS_pidfd_send_signal */
+
+/* Fallback syscall number for pivot_root */
+/* #undef SYS_pivot_root */
+
+/* Fallback syscall number for prlimit64 */
+/* #undef SYS_prlimit64 */
+
+/* Fallback syscall number for sched_getaffinity */
+/* #undef SYS_sched_getaffinity */
+
+/* Fallback syscall number for sched_setattr */
+/* #undef SYS_sched_setattr */
+
+/* Fallback syscall number for setns */
+/* #undef SYS_setns */
+
+/* Fallback syscall number for swapoff */
+/* #undef SYS_swapoff */
+
+/* Fallback syscall number for swapon */
+/* #undef SYS_swapon */
+
+/* Fallback syscall number for unshare */
+/* #undef SYS_unshare */
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enables colorized output from utils by default */
+#define USE_COLORS_BY_DEFAULT 1
+
+/* Define to 1 if want to use CMOS clock. */
+#define USE_HWCLOCK_CMOS 1
+
+/* use datetime parsing GPLv3 code to hwclock */
+#define USE_HWCLOCK_GPLv3_DATETIME 1
+
+/* Define to 1 if want to support mtab. */
+/* #undef USE_LIBMOUNT_SUPPORT_MTAB */
+
+/* Define to 1 if want to support namepaces. */
+#define USE_LIBMOUNT_SUPPORT_NAMESPACES 1
+
+/* Enable plymouth support feature for sulogin and aggety */
+#define USE_PLYMOUTH_SUPPORT 1
+
+/* Should sulogin use a emergency mount of /dev and /proc? */
+/* #undef USE_SULOGIN_EMERGENCY_MOUNT */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Should wall and write be installed setgid tty? */
+#define USE_TTY_GROUP 1
+
+/* Define to 1 to remove /bin and /sbin from PATH env.variable */
+/* #undef USE_USRDIR_PATHS_ONLY */
+
+/* Define to 1 to use vendordir */
+/* #undef USE_VENDORDIR */
+
+/* Version number of package */
+#define VERSION "@VERSION@"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Enable MAP_ANON in sys/mman.h on Mac OS X */
+/* #undef _DARWIN_C_SOURCE */
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+ code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
diff --git a/src/utils/include/all-io.h b/src/utils/include/all-io.h
new file mode 100644
index 0000000..8ffa9cf
--- /dev/null
+++ b/src/utils/include/all-io.h
@@ -0,0 +1,81 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ * Petr Uzel <petr.uzel@suse.cz>
+ */
+
+#ifndef UTIL_LINUX_ALL_IO_H
+#define UTIL_LINUX_ALL_IO_H
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "c.h"
+
+static inline int write_all(int fd, const void *buf, size_t count)
+{
+ while (count) {
+ ssize_t tmp;
+
+ errno = 0;
+ tmp = write(fd, buf, count);
+ if (tmp > 0) {
+ count -= tmp;
+ if (count)
+ buf = (const void *) ((const char *) buf + tmp);
+ } else if (errno != EINTR && errno != EAGAIN)
+ return -1;
+ if (errno == EAGAIN) /* Try later, *sigh* */
+ xusleep(250000);
+ }
+ return 0;
+}
+
+static inline int fwrite_all(const void *ptr, size_t size,
+ size_t nmemb, FILE *stream)
+{
+ while (nmemb) {
+ size_t tmp;
+
+ errno = 0;
+ tmp = fwrite(ptr, size, nmemb, stream);
+ if (tmp > 0) {
+ nmemb -= tmp;
+ if (nmemb)
+ ptr = (const void *) ((const char *) ptr + (tmp * size));
+ } else if (errno != EINTR && errno != EAGAIN)
+ return -1;
+ if (errno == EAGAIN) /* Try later, *sigh* */
+ xusleep(250000);
+ }
+ return 0;
+}
+
+static inline ssize_t read_all(int fd, char *buf, size_t count)
+{
+ ssize_t ret;
+ ssize_t c = 0;
+ int tries = 0;
+
+ memset(buf, 0, count);
+ while (count > 0) {
+ ret = read(fd, buf, count);
+ if (ret <= 0) {
+ if (ret < 0 && (errno == EAGAIN || errno == EINTR) && (tries++ < 5)) {
+ xusleep(250000);
+ continue;
+ }
+ return c ? c : -1;
+ }
+ tries = 0;
+ count -= ret;
+ buf += ret;
+ c += ret;
+ }
+ return c;
+}
+
+#endif /* UTIL_LINUX_ALL_IO_H */
diff --git a/src/utils/include/bitops.h b/src/utils/include/bitops.h
new file mode 100644
index 0000000..287d4af
--- /dev/null
+++ b/src/utils/include/bitops.h
@@ -0,0 +1,150 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include <stdint.h>
+#include <sys/param.h>
+
+#if defined(HAVE_BYTESWAP_H)
+# include <byteswap.h>
+#endif
+
+#if defined(HAVE_ENDIAN_H)
+# include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H) /* BSDs have them here */
+# include <sys/endian.h>
+#endif
+
+#if defined(__OpenBSD__)
+# include <sys/types.h>
+# define be16toh(x) betoh16(x)
+# define be32toh(x) betoh32(x)
+# define be64toh(x) betoh64(x)
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+# define bswap_16(x) bswap16(x)
+# define bswap_32(x) bswap32(x)
+# define bswap_64(x) bswap64(x)
+#elif defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+# define htobe16(x) OSSwapHostToBigInt16(x)
+# define htole16(x) OSSwapHostToLittleInt16(x)
+# define be16toh(x) OSSwapBigToHostInt16(x)
+# define le16toh(x) OSSwapLittleToHostInt16(x)
+# define htobe32(x) OSSwapHostToBigInt32(x)
+# define htole32(x) OSSwapHostToLittleInt32(x)
+# define be32toh(x) OSSwapBigToHostInt32(x)
+# define le32toh(x) OSSwapLittleToHostInt32(x)
+# define htobe64(x) OSSwapHostToBigInt64(x)
+# define htole64(x) OSSwapHostToLittleInt64(x)
+# define be64toh(x) OSSwapBigToHostInt64(x)
+# define le64toh(x) OSSwapLittleToHostInt64(x)
+# define bswap_16(x) OSSwapInt16(x)
+# define bswap_32(x) OSSwapInt32(x)
+# define bswap_64(x) OSSwapInt64(x)
+#endif
+
+/*
+ * Fallbacks
+ * casts are necessary for constants, because we never know how for sure
+ * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
+ */
+#ifndef bswap_16
+# define bswap_16(x) ((uint16_t)( \
+ (((uint16_t)(x) & 0x00FF) << 8) | \
+ (((uint16_t)(x) & 0xFF00) >> 8)))
+#endif
+
+#ifndef bswap_32
+# define bswap_32(x) ((uint32_t)( \
+ (((uint32_t)(x) & 0x000000FF) << 24) | \
+ (((uint32_t)(x) & 0x0000FF00) << 8) | \
+ (((uint32_t)(x) & 0x00FF0000) >> 8) | \
+ (((uint32_t)(x) & 0xFF000000) >> 24)))
+#endif
+
+#ifndef bswap_64
+# define bswap_64(x) ((uint64_t)( \
+ (((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \
+ (((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \
+ (((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x00000000FF000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x000000FF00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0xFF00000000000000ULL) >> 56)))
+#endif
+
+#ifndef htobe16
+# if !defined(WORDS_BIGENDIAN)
+# define htobe16(x) bswap_16 (x)
+# define htole16(x) (x)
+# define be16toh(x) bswap_16 (x)
+# define le16toh(x) (x)
+# define htobe32(x) bswap_32 (x)
+# define htole32(x) (x)
+# define be32toh(x) bswap_32 (x)
+# define le32toh(x) (x)
+# define htobe64(x) bswap_64 (x)
+# define htole64(x) (x)
+# define be64toh(x) bswap_64 (x)
+# define le64toh(x) (x)
+# else
+# define htobe16(x) (x)
+# define htole16(x) bswap_16 (x)
+# define be16toh(x) (x)
+# define le16toh(x) bswap_16 (x)
+# define htobe32(x) (x)
+# define htole32(x) bswap_32 (x)
+# define be32toh(x) (x)
+# define le32toh(x) bswap_32 (x)
+# define htobe64(x) (x)
+# define htole64(x) bswap_64 (x)
+# define be64toh(x) (x)
+# define le64toh(x) bswap_64 (x)
+# endif
+#endif
+
+/*
+ * Byte swab macros (based on linux/byteorder/swab.h)
+ */
+#define swab16(x) bswap_16(x)
+#define swab32(x) bswap_32(x)
+#define swab64(x) bswap_64(x)
+
+#define cpu_to_le16(x) ((uint16_t) htole16(x))
+#define cpu_to_le32(x) ((uint32_t) htole32(x))
+#define cpu_to_le64(x) ((uint64_t) htole64(x))
+
+#define cpu_to_be16(x) ((uint16_t) htobe16(x))
+#define cpu_to_be32(x) ((uint32_t) htobe32(x))
+#define cpu_to_be64(x) ((uint64_t) htobe64(x))
+
+#define le16_to_cpu(x) ((uint16_t) le16toh(x))
+#define le32_to_cpu(x) ((uint32_t) le32toh(x))
+#define le64_to_cpu(x) ((uint64_t) le64toh(x))
+
+#define be16_to_cpu(x) ((uint16_t) be16toh(x))
+#define be32_to_cpu(x) ((uint32_t) be32toh(x))
+#define be64_to_cpu(x) ((uint64_t) be64toh(x))
+
+/*
+ * Bit map related macros. Usually provided by libc.
+ */
+#ifndef NBBY
+# define NBBY CHAR_BIT
+#endif
+
+#ifndef setbit
+# define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+# define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+# define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+# define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+#endif /* BITOPS_H */
+
diff --git a/src/utils/include/blkdev.h b/src/utils/include/blkdev.h
new file mode 100644
index 0000000..6cbecbb
--- /dev/null
+++ b/src/utils/include/blkdev.h
@@ -0,0 +1,151 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef BLKDEV_H
+#define BLKDEV_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCCOM_H
+# include <sys/ioccom.h> /* for _IO macro on e.g. Solaris */
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_MKDEV_H
+# include <sys/mkdev.h> /* major and minor on Solaris */
+#endif
+
+#define DEFAULT_SECTOR_SIZE 512
+
+#ifdef __linux__
+/* very basic ioctls, should be available everywhere */
+# ifndef BLKROSET
+# define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */
+# define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
+# define BLKRRPART _IO(0x12,95) /* re-read partition table */
+# define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
+# define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
+# define BLKRASET _IO(0x12,98) /* set read ahead for block device */
+# define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
+# define BLKFRASET _IO(0x12,100) /* set filesystem (mm/filemap.c) read-ahead */
+# define BLKFRAGET _IO(0x12,101) /* get filesystem (mm/filemap.c) read-ahead */
+# define BLKSECTSET _IO(0x12,102) /* set max sectors per request (ll_rw_blk.c) */
+# define BLKSECTGET _IO(0x12,103) /* get max sectors per request (ll_rw_blk.c) */
+# define BLKSSZGET _IO(0x12,104) /* get block device sector size */
+
+/* ioctls introduced in 2.2.16, removed in 2.5.58 */
+# define BLKELVGET _IOR(0x12,106,size_t) /* elevator get */
+# define BLKELVSET _IOW(0x12,107,size_t) /* elevator set */
+
+# define BLKBSZGET _IOR(0x12,112,size_t)
+# define BLKBSZSET _IOW(0x12,113,size_t)
+# endif /* !BLKROSET */
+
+# ifndef BLKGETSIZE64
+# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
+# endif
+
+/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */
+# ifndef BLKIOMIN
+# define BLKIOMIN _IO(0x12,120)
+# define BLKIOOPT _IO(0x12,121)
+# define BLKALIGNOFF _IO(0x12,122)
+# define BLKPBSZGET _IO(0x12,123)
+# endif
+
+/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */
+# ifndef BLKDISCARDZEROES
+# define BLKDISCARDZEROES _IO(0x12,124)
+# endif
+
+/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */
+# ifndef FIFREEZE
+# define FIFREEZE _IOWR('X', 119, int) /* Freeze */
+# define FITHAW _IOWR('X', 120, int) /* Thaw */
+# endif
+
+/* uniform CD-ROM information */
+# ifndef CDROM_GET_CAPABILITY
+# define CDROM_GET_CAPABILITY 0x5331
+# endif
+
+#endif /* __linux */
+
+
+#ifdef APPLE_DARWIN
+# define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif
+
+#ifndef HDIO_GETGEO
+# ifdef __linux__
+# define HDIO_GETGEO 0x0301
+# endif
+
+struct hd_geometry {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders; /* truncated */
+ unsigned long start;
+};
+#endif /* HDIO_GETGEO */
+
+
+/* are we working with block device? */
+int is_blkdev(int fd);
+
+/* open block device or file */
+int open_blkdev_or_file(const struct stat *st, const char *name, const int oflag);
+
+/* Determine size in bytes */
+off_t blkdev_find_size (int fd);
+
+/* get size in bytes */
+int blkdev_get_size(int fd, unsigned long long *bytes);
+
+/* get 512-byte sector count */
+int blkdev_get_sectors(int fd, unsigned long long *sectors);
+
+/* get hardware sector size */
+int blkdev_get_sector_size(int fd, int *sector_size);
+
+/* specifies whether or not the device is misaligned */
+int blkdev_is_misaligned(int fd);
+
+/* get physical block device size */
+int blkdev_get_physector_size(int fd, int *sector_size);
+
+/* is the device cdrom capable? */
+int blkdev_is_cdrom(int fd);
+
+/* get device's geometry - legacy */
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s);
+
+/* SCSI device types. Copied almost as-is from kernel header.
+ * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/scsi/scsi.h */
+#define SCSI_TYPE_DISK 0x00
+#define SCSI_TYPE_TAPE 0x01
+#define SCSI_TYPE_PRINTER 0x02
+#define SCSI_TYPE_PROCESSOR 0x03 /* HP scanners use this */
+#define SCSI_TYPE_WORM 0x04 /* Treated as ROM by our system */
+#define SCSI_TYPE_ROM 0x05
+#define SCSI_TYPE_SCANNER 0x06
+#define SCSI_TYPE_MOD 0x07 /* Magneto-optical disk - treated as SCSI_TYPE_DISK */
+#define SCSI_TYPE_MEDIUM_CHANGER 0x08
+#define SCSI_TYPE_COMM 0x09 /* Communications device */
+#define SCSI_TYPE_RAID 0x0c
+#define SCSI_TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
+#define SCSI_TYPE_RBC 0x0e
+#define SCSI_TYPE_OSD 0x11
+#define SCSI_TYPE_NO_LUN 0x7f
+
+/* convert scsi type code to name */
+const char *blkdev_scsi_type_to_name(int type);
+
+int blkdev_lock(int fd, const char *devname, const char *lockmode);
+
+#endif /* BLKDEV_H */
diff --git a/src/utils/include/c.h b/src/utils/include/c.h
new file mode 100644
index 0000000..ae08131
--- /dev/null
+++ b/src/utils/include/c.h
@@ -0,0 +1,427 @@
+/*
+ * Fundamental C definitions.
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ */
+#ifndef UTIL_LINUX_C_H
+#define UTIL_LINUX_C_H
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#ifdef HAVE_ERR_H
+# include <err.h>
+#endif
+
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h> /* for major, minor */
+#endif
+
+#ifndef LOGIN_NAME_MAX
+# define LOGIN_NAME_MAX 256
+#endif
+
+#ifndef NAME_MAX
+# define NAME_MAX PATH_MAX
+#endif
+
+/*
+ * __GNUC_PREREQ is deprecated in favour of __has_attribute() and
+ * __has_feature(). The __has macros are supported by clang and gcc>=5.
+ */
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+# define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifdef __GNUC__
+
+/* &a[0] degrades to a pointer: a different type from an array */
+# define __must_be_array(a) \
+ UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0])))
+
+# define ignore_result(x) __extension__ ({ \
+ __typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \
+})
+
+#else /* !__GNUC__ */
+# define __must_be_array(a) 0
+# define __attribute__(_arg_)
+# define ignore_result(x) ((void) (x))
+#endif /* !__GNUC__ */
+
+/*
+ * It evaluates to 1 if the attribute/feature is supported by the current
+ * compilation target. Fallback for old compilers.
+ */
+#ifndef __has_attribute
+ #define __has_attribute(x) 0
+#endif
+
+#ifndef __has_feature
+ #define __has_feature(x) 0
+#endif
+
+/*
+ * Function attributes
+ */
+#ifndef __ul_alloc_size
+# if (__has_attribute(alloc_size) && __has_attribute(warn_unused_result)) || __GNUC_PREREQ (4, 3)
+# define __ul_alloc_size(s) __attribute__((alloc_size(s), warn_unused_result))
+# else
+# define __ul_alloc_size(s)
+# endif
+#endif
+
+#ifndef __ul_calloc_size
+# if (__has_attribute(alloc_size) && __has_attribute(warn_unused_result)) || __GNUC_PREREQ (4, 3)
+# define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s), warn_unused_result))
+# else
+# define __ul_calloc_size(n, s)
+# endif
+#endif
+
+#if __has_attribute(returns_nonnull) || __GNUC_PREREQ (4, 9)
+# define __ul_returns_nonnull __attribute__((returns_nonnull))
+#else
+# define __ul_returns_nonnull
+#endif
+
+/*
+ * Force a compilation error if condition is true, but also produce a
+ * result (of value 0 and type size_t), so the expression can be used
+ * e.g. in a structure initializer (or wherever else comma expressions
+ * aren't permitted).
+ */
+#define UL_BUILD_BUG_ON_ZERO(e) __extension__ (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef min
+# define min(x, y) __extension__ ({ \
+ __typeof__(x) _min1 = (x); \
+ __typeof__(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#ifndef max
+# define max(x, y) __extension__ ({ \
+ __typeof__(x) _max1 = (x); \
+ __typeof__(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+#endif
+
+#ifndef cmp_numbers
+# define cmp_numbers(x, y) __extension__ ({ \
+ __typeof__(x) _a = (x); \
+ __typeof__(y) _b = (y); \
+ (void) (&_a == &_b); \
+ _a == _b ? 0 : _a > _b ? 1 : -1; })
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/*
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ */
+#ifndef container_of
+#define container_of(ptr, type, member) __extension__ ({ \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
+# ifdef HAVE___PROGNAME
+extern char *__progname;
+# define program_invocation_short_name __progname
+# else
+# ifdef HAVE_GETEXECNAME
+# define program_invocation_short_name \
+ prog_inv_sh_nm_from_file(getexecname(), 0)
+# else
+# define program_invocation_short_name \
+ prog_inv_sh_nm_from_file(__FILE__, 1)
+# endif
+static char prog_inv_sh_nm_buf[256];
+static inline char *
+prog_inv_sh_nm_from_file(char *f, char stripext)
+{
+ char *t;
+
+ if ((t = strrchr(f, '/')) != NULL)
+ t++;
+ else
+ t = f;
+
+ strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1);
+ prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0';
+
+ if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL)
+ *t = '\0';
+
+ return prog_inv_sh_nm_buf;
+}
+# endif
+#endif
+
+
+#ifndef HAVE_ERR_H
+static inline void
+errmsg(char doexit, int excode, char adderr, const char *fmt, ...)
+{
+ fprintf(stderr, "%s: ", program_invocation_short_name);
+ if (fmt != NULL) {
+ va_list argp;
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+ if (adderr)
+ fprintf(stderr, ": ");
+ }
+ if (adderr)
+ fprintf(stderr, "%m");
+ fprintf(stderr, "\n");
+ if (doexit)
+ exit(excode);
+}
+
+#ifndef HAVE_ERR
+# define err(E, FMT...) errmsg(1, E, 1, FMT)
+#endif
+
+#ifndef HAVE_ERRX
+# define errx(E, FMT...) errmsg(1, E, 0, FMT)
+#endif
+
+#ifndef HAVE_WARN
+# define warn(FMT...) errmsg(0, 0, 1, FMT)
+#endif
+
+#ifndef HAVE_WARNX
+# define warnx(FMT...) errmsg(0, 0, 0, FMT)
+#endif
+#endif /* !HAVE_ERR_H */
+
+
+/* Don't use inline function to avoid '#include "nls.h"' in c.h
+ */
+#define errtryhelp(eval) __extension__ ({ \
+ fprintf(stderr, _("Try '%s --help' for more information.\n"), \
+ program_invocation_short_name); \
+ exit(eval); \
+})
+
+/* After failed execvp() */
+#define EX_EXEC_FAILED 126 /* Program located, but not usable. */
+#define EX_EXEC_ENOENT 127 /* Could not find program to exec. */
+#define errexec(name) err(errno == ENOENT ? EX_EXEC_ENOENT : EX_EXEC_FAILED, \
+ _("failed to execute %s"), name)
+
+
+static inline __attribute__((const)) int is_power_of_2(unsigned long num)
+{
+ return (num != 0 && ((num & (num - 1)) == 0));
+}
+
+#ifndef HAVE_LOFF_T
+typedef int64_t loff_t;
+#endif
+
+#if !defined(HAVE_DIRFD) && (!defined(HAVE_DECL_DIRFD) || HAVE_DECL_DIRFD == 0) && defined(HAVE_DIR_DD_FD)
+#include <sys/types.h>
+#include <dirent.h>
+static inline int dirfd(DIR *d)
+{
+ return d->dd_fd;
+}
+#endif
+
+/*
+ * Fallback defines for old versions of glibc
+ */
+#include <fcntl.h>
+
+#ifdef O_CLOEXEC
+#define UL_CLOEXECSTR "e"
+#else
+#define UL_CLOEXECSTR ""
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#ifdef __FreeBSD_kernel__
+#ifndef F_DUPFD_CLOEXEC
+#define F_DUPFD_CLOEXEC 17 /* Like F_DUPFD, but FD_CLOEXEC is set */
+#endif
+#endif
+
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x0020
+#endif
+
+#ifndef IUTF8
+#define IUTF8 0040000
+#endif
+
+/*
+ * MAXHOSTNAMELEN replacement
+ */
+static inline size_t get_hostname_max(void)
+{
+ long len = sysconf(_SC_HOST_NAME_MAX);
+
+ if (0 < len)
+ return len;
+
+#ifdef MAXHOSTNAMELEN
+ return MAXHOSTNAMELEN;
+#elif HOST_NAME_MAX
+ return HOST_NAME_MAX;
+#endif
+ return 64;
+}
+
+/*
+ * The usleep function was marked obsolete in POSIX.1-2001 and was removed
+ * in POSIX.1-2008. It was replaced with nanosleep() that provides more
+ * advantages (like no interaction with signals and other timer functions).
+ */
+#include <time.h>
+
+static inline int xusleep(useconds_t usec)
+{
+#ifdef HAVE_NANOSLEEP
+ struct timespec waittime = {
+ .tv_sec = usec / 1000000L,
+ .tv_nsec = (usec % 1000000L) * 1000
+ };
+ return nanosleep(&waittime, NULL);
+#elif defined(HAVE_USLEEP)
+ return usleep(usec);
+#else
+# error "System with usleep() or nanosleep() required!"
+#endif
+}
+
+/*
+ * Constant strings for usage() functions. For more info see
+ * Documentation/{howto-usage-function.txt,boilerplate.c}
+ */
+#define USAGE_HEADER _("\nUsage:\n")
+#define USAGE_OPTIONS _("\nOptions:\n")
+#define USAGE_FUNCTIONS _("\nFunctions:\n")
+#define USAGE_COMMANDS _("\nCommands:\n")
+#define USAGE_ARGUMENTS _("\nArguments:\n")
+#define USAGE_COLUMNS _("\nAvailable output columns:\n")
+#define USAGE_SEPARATOR "\n"
+
+#define USAGE_OPTSTR_HELP _("display this help")
+#define USAGE_OPTSTR_VERSION _("display version")
+
+#define USAGE_HELP_OPTIONS(marg_dsc) \
+ "%-" #marg_dsc "s%s\n" \
+ "%-" #marg_dsc "s%s\n" \
+ , " -h, --help", USAGE_OPTSTR_HELP \
+ , " -V, --version", USAGE_OPTSTR_VERSION
+
+#define USAGE_ARG_SEPARATOR "\n"
+#define USAGE_ARG_SIZE(_name) \
+ _(" %s arguments may be followed by the suffixes for\n" \
+ " GiB, TiB, PiB, EiB, ZiB, and YiB (the \"iB\" is optional)\n"), _name
+
+#define USAGE_MAN_TAIL(_man) _("\nFor more details see %s.\n"), _man
+
+#define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING
+
+#define print_version(eval) __extension__ ({ \
+ printf(UTIL_LINUX_VERSION); \
+ exit(eval); \
+})
+
+/*
+ * seek stuff
+ */
+#ifndef SEEK_DATA
+# define SEEK_DATA 3
+#endif
+#ifndef SEEK_HOLE
+# define SEEK_HOLE 4
+#endif
+
+
+/*
+ * Macros to convert #define'itions to strings, for example
+ * #define XYXXY 42
+ * printf ("%s=%s\n", stringify(XYXXY), stringify_value(XYXXY));
+ */
+#define stringify_value(s) stringify(s)
+#define stringify(s) #s
+
+/*
+ * UL_ASAN_BLACKLIST is a macro to tell AddressSanitizer (a compile-time
+ * instrumentation shipped with Clang and GCC) to not instrument the
+ * annotated function. Furthermore, it will prevent the compiler from
+ * inlining the function because inlining currently breaks the blacklisting
+ * mechanism of AddressSanitizer.
+ */
+#if __has_feature(address_sanitizer) && __has_attribute(no_sanitize_memory) && __has_attribute(no_sanitize_address)
+# define UL_ASAN_BLACKLIST __attribute__((noinline)) __attribute__((no_sanitize_memory)) __attribute__((no_sanitize_address))
+#else
+# define UL_ASAN_BLACKLIST /* nothing */
+#endif
+
+/*
+ * Note that sysconf(_SC_GETPW_R_SIZE_MAX) returns *initial* suggested size for
+ * pwd buffer and in some cases it is not large enough. See POSIX and
+ * getpwnam_r man page for more details.
+ */
+#define UL_GETPW_BUFSIZ (16 * 1024)
+
+/*
+ * Darwin or other BSDs may only have MAP_ANON. To get it on Darwin we must
+ * define _DARWIN_C_SOURCE before including sys/mman.h. We do this in config.h.
+ */
+#if !defined MAP_ANONYMOUS && defined MAP_ANON
+# define MAP_ANONYMOUS (MAP_ANON)
+#endif
+
+#endif /* UTIL_LINUX_C_H */
diff --git a/src/utils/include/canonicalize.h b/src/utils/include/canonicalize.h
new file mode 100644
index 0000000..ff6ef0d
--- /dev/null
+++ b/src/utils/include/canonicalize.h
@@ -0,0 +1,32 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library Public License for more details.
+ */
+#ifndef CANONICALIZE_H
+#define CANONICALIZE_H
+
+#include "c.h" /* for PATH_MAX */
+#include "strutils.h"
+
+extern char *canonicalize_path(const char *path);
+extern char *canonicalize_path_restricted(const char *path);
+extern char *canonicalize_dm_name(const char *ptname);
+extern char *__canonicalize_dm_name(const char *prefix, const char *ptname);
+
+extern char *absolute_path(const char *path);
+
+static inline int is_relative_path(const char *path)
+{
+ if (!path || *path == '/')
+ return 0;
+ return 1;
+}
+
+#endif /* CANONICALIZE_H */
diff --git a/src/utils/include/caputils.h b/src/utils/include/caputils.h
new file mode 100644
index 0000000..852903a
--- /dev/null
+++ b/src/utils/include/caputils.h
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef CAPUTILS_H
+#define CAPUTILS_H
+
+#include <linux/capability.h>
+
+#ifndef PR_CAP_AMBIENT
+# define PR_CAP_AMBIENT 47
+# define PR_CAP_AMBIENT_IS_SET 1
+# define PR_CAP_AMBIENT_RAISE 2
+# define PR_CAP_AMBIENT_LOWER 3
+#endif
+
+extern int capset(cap_user_header_t header, cap_user_data_t data);
+extern int capget(cap_user_header_t header, const cap_user_data_t data);
+
+extern int cap_last_cap(void);
+
+#endif /* CAPUTILS_H */
diff --git a/src/utils/include/carefulputc.h b/src/utils/include/carefulputc.h
new file mode 100644
index 0000000..f1c0356
--- /dev/null
+++ b/src/utils/include/carefulputc.h
@@ -0,0 +1,155 @@
+#ifndef UTIL_LINUX_CAREFULPUTC_H
+#define UTIL_LINUX_CAREFULPUTC_H
+
+/*
+ * A putc() for use in write and wall (that sometimes are sgid tty).
+ * It avoids control characters in our locale, and also ASCII control
+ * characters. Note that the locale of the recipient is unknown.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "cctype.h"
+
+static inline int fputc_careful(int c, FILE *fp, const char fail)
+{
+ int ret;
+
+ if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
+ ret = putc(c, fp);
+ else if (!c_isascii(c))
+ ret = fprintf(fp, "\\%3o", (unsigned char)c);
+ else {
+ ret = putc(fail, fp);
+ if (ret != EOF)
+ ret = putc(c ^ 0x40, fp);
+ }
+ return (ret < 0) ? EOF : 0;
+}
+
+/*
+ * Requirements enumerated via testing (V8, Firefox, IE11):
+ *
+ * var charsToEscape = [];
+ * for (var i = 0; i < 65535; i += 1) {
+ * try {
+ * JSON.parse('{"sample": "' + String.fromCodePoint(i) + '"}');
+ * } catch (e) {
+ * charsToEscape.push(i);
+ * }
+ * }
+ */
+static inline void fputs_quoted_case_json(const char *data, FILE *out, int dir)
+{
+ const char *p;
+
+ fputc('"', out);
+ for (p = data; p && *p; p++) {
+
+ const unsigned char c = (unsigned char) *p;
+
+ /* From http://www.json.org
+ *
+ * The double-quote and backslashes would break out a string or
+ * init an escape sequence if not escaped.
+ *
+ * Note that single-quotes and forward slashes, while they're
+ * in the JSON spec, don't break double-quoted strings.
+ */
+ if (c == '"' || c == '\\') {
+ fputc('\\', out);
+ fputc(c, out);
+ continue;
+ }
+
+ /* All non-control characters OK; do the case swap as required. */
+ if (c >= 0x20) {
+ fputc(dir == 1 ? toupper(c) :
+ dir == -1 ? tolower(c) : *p, out);
+ continue;
+ }
+
+ /* In addition, all chars under ' ' break Node's/V8/Chrome's, and
+ * Firefox's JSON.parse function
+ */
+ switch (c) {
+ /* Handle short-hand cases to reduce output size. C
+ * has most of the same stuff here, so if there's an
+ * "Escape for C" function somewhere in the STL, we
+ * should probably be using it.
+ */
+ case '\b':
+ fputs("\\b", out);
+ break;
+ case '\t':
+ fputs("\\t", out);
+ break;
+ case '\n':
+ fputs("\\n", out);
+ break;
+ case '\f':
+ fputs("\\f", out);
+ break;
+ case '\r':
+ fputs("\\r", out);
+ break;
+ default:
+ /* Other assorted control characters */
+ fprintf(out, "\\u00%02x", c);
+ break;
+ }
+ }
+ fputc('"', out);
+}
+
+
+static inline void fputs_quoted_case(const char *data, FILE *out, int dir)
+{
+ const char *p;
+
+ fputc('"', out);
+ for (p = data; p && *p; p++) {
+ if ((unsigned char) *p == 0x22 || /* " */
+ (unsigned char) *p == 0x5c || /* \ */
+ (unsigned char) *p == 0x60 || /* ` */
+ (unsigned char) *p == 0x24 || /* $ */
+ !isprint((unsigned char) *p) ||
+ iscntrl((unsigned char) *p)) {
+
+ fprintf(out, "\\x%02x", (unsigned char) *p);
+ } else
+ fputc(dir == 1 ? toupper(*p) :
+ dir == -1 ? tolower(*p) :
+ *p, out);
+ }
+ fputc('"', out);
+}
+
+#define fputs_quoted(_d, _o) fputs_quoted_case(_d, _o, 0)
+#define fputs_quoted_upper(_d, _o) fputs_quoted_case(_d, _o, 1)
+#define fputs_quoted_lower(_d, _o) fputs_quoted_case(_d, _o, -1)
+
+#define fputs_quoted_json(_d, _o) fputs_quoted_case_json(_d, _o, 0)
+#define fputs_quoted_json_upper(_d, _o) fputs_quoted_case_json(_d, _o, 1)
+#define fputs_quoted_json_lower(_d, _o) fputs_quoted_case_json(_d, _o, -1)
+
+static inline void fputs_nonblank(const char *data, FILE *out)
+{
+ const char *p;
+
+ for (p = data; p && *p; p++) {
+ if (isblank((unsigned char) *p) ||
+ (unsigned char) *p == 0x5c || /* \ */
+ !isprint((unsigned char) *p) ||
+ iscntrl((unsigned char) *p)) {
+
+ fprintf(out, "\\x%02x", (unsigned char) *p);
+
+ } else
+ fputc(*p, out);
+ }
+}
+
+
+#endif /* _CAREFULPUTC_H */
diff --git a/src/utils/include/cctype.h b/src/utils/include/cctype.h
new file mode 100644
index 0000000..6ab644c
--- /dev/null
+++ b/src/utils/include/cctype.h
@@ -0,0 +1,325 @@
+/**
+ * Character handling in C locale.
+ *
+ * This file is based on gnulib c-ctype.h-dd7a871 with the
+ * other gnulib dependencies removed for use in util-linux.
+ *
+ * These functions work like the corresponding functions in <ctype.h>,
+ * except that they have the C (POSIX) locale hardwired, whereas the
+ * <ctype.h> functions' behaviour depends on the current locale set via
+ * setlocale.
+ *
+ * Copyright (C) 2000-2003, 2006, 2008-2017 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UTIL_LINUX_CCTYPE_H
+#define UTIL_LINUX_CCTYPE_H
+
+/**
+ * The functions defined in this file assume the "C" locale and a character
+ * set without diacritics (ASCII-US or EBCDIC-US or something like that).
+ * Even if the "C" locale on a particular system is an extension of the ASCII
+ * character set (like on BeOS, where it is UTF-8, or on AmigaOS, where it
+ * is ISO-8859-1), the functions in this file recognize only the ASCII
+ * characters.
+ */
+
+#if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)
+
+/*
+ * The character set is ASCII or one of its variants or extensions, not EBCDIC.
+ * Testing the value of '\n' and '\r' is not relevant.
+ */
+# define C_CTYPE_ASCII 1
+#elif ! (' ' == '\x40' && '0' == '\xf0' \
+ && 'A' == '\xc1' && 'J' == '\xd1' && 'S' == '\xe2' \
+ && 'a' == '\x81' && 'j' == '\x91' && 's' == '\xa2')
+# error "Only ASCII and EBCDIC are supported"
+#endif
+
+#if 'A' < 0
+# error "EBCDIC and char is signed -- not supported"
+#endif
+
+/* Cases for control characters. */
+#define _C_CTYPE_CNTRL \
+ case '\a': case '\b': case '\f': case '\n': \
+ case '\r': case '\t': case '\v': \
+ _C_CTYPE_OTHER_CNTRL
+
+/* ASCII control characters other than those with \-letter escapes. */
+#if C_CTYPE_ASCII
+# define _C_CTYPE_OTHER_CNTRL \
+ case '\x00': case '\x01': case '\x02': case '\x03': \
+ case '\x04': case '\x05': case '\x06': case '\x0e': \
+ case '\x0f': case '\x10': case '\x11': case '\x12': \
+ case '\x13': case '\x14': case '\x15': case '\x16': \
+ case '\x17': case '\x18': case '\x19': case '\x1a': \
+ case '\x1b': case '\x1c': case '\x1d': case '\x1e': \
+ case '\x1f': case '\x7f'
+#else
+
+/*
+ * Use EBCDIC code page 1047's assignments for ASCII control chars;
+ * assume all EBCDIC code pages agree about these assignments.
+ */
+# define _C_CTYPE_OTHER_CNTRL \
+ case '\x00': case '\x01': case '\x02': case '\x03': \
+ case '\x07': case '\x0e': case '\x0f': case '\x10': \
+ case '\x11': case '\x12': case '\x13': case '\x18': \
+ case '\x19': case '\x1c': case '\x1d': case '\x1e': \
+ case '\x1f': case '\x26': case '\x27': case '\x2d': \
+ case '\x2e': case '\x32': case '\x37': case '\x3c': \
+ case '\x3d': case '\x3f'
+#endif
+
+/* Cases for lowercase hex letters, and lowercase letters, all offset by N. */
+#define _C_CTYPE_LOWER_A_THRU_F_N(N) \
+ case 'a' + (N): case 'b' + (N): case 'c' + (N): case 'd' + (N): \
+ case 'e' + (N): case 'f' + (N)
+#define _C_CTYPE_LOWER_N(N) \
+ _C_CTYPE_LOWER_A_THRU_F_N(N): \
+ case 'g' + (N): case 'h' + (N): case 'i' + (N): case 'j' + (N): \
+ case 'k' + (N): case 'l' + (N): case 'm' + (N): case 'n' + (N): \
+ case 'o' + (N): case 'p' + (N): case 'q' + (N): case 'r' + (N): \
+ case 's' + (N): case 't' + (N): case 'u' + (N): case 'v' + (N): \
+ case 'w' + (N): case 'x' + (N): case 'y' + (N): case 'z' + (N)
+
+/* Cases for hex letters, digits, lower, punct, and upper. */
+#define _C_CTYPE_A_THRU_F \
+ _C_CTYPE_LOWER_A_THRU_F_N (0): \
+ _C_CTYPE_LOWER_A_THRU_F_N ('A' - 'a')
+#define _C_CTYPE_DIGIT \
+ case '0': case '1': case '2': case '3': \
+ case '4': case '5': case '6': case '7': \
+ case '8': case '9'
+#define _C_CTYPE_LOWER _C_CTYPE_LOWER_N (0)
+#define _C_CTYPE_PUNCT \
+ case '!': case '"': case '#': case '$': \
+ case '%': case '&': case '\'': case '(': \
+ case ')': case '*': case '+': case ',': \
+ case '-': case '.': case '/': case ':': \
+ case ';': case '<': case '=': case '>': \
+ case '?': case '@': case '[': case '\\': \
+ case ']': case '^': case '_': case '`': \
+ case '{': case '|': case '}': case '~'
+#define _C_CTYPE_UPPER _C_CTYPE_LOWER_N ('A' - 'a')
+
+/**
+ * Function definitions.
+ *
+ * Unlike the functions in <ctype.h>, which require an argument in the range
+ * of the 'unsigned char' type, the functions here operate on values that are
+ * in the 'unsigned char' range or in the 'char' range. In other words,
+ * when you have a 'char' value, you need to cast it before using it as
+ * argument to a <ctype.h> function:
+ *
+ * const char *s = ...;
+ * if (isalpha ((unsigned char) *s)) ...
+ *
+ * but you don't need to cast it for the functions defined in this file:
+ *
+ * const char *s = ...;
+ * if (c_isalpha (*s)) ...
+ */
+
+static inline int c_isalnum (int c)
+{
+ switch (c) {
+ _C_CTYPE_DIGIT:
+ _C_CTYPE_LOWER:
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isalpha (int c)
+{
+ switch (c) {
+ _C_CTYPE_LOWER:
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* The function isascii is not locale dependent.
+ * Its use in EBCDIC is questionable.
+ */
+static inline int c_isascii (int c)
+{
+ switch (c) {
+ case ' ':
+ _C_CTYPE_CNTRL:
+ _C_CTYPE_DIGIT:
+ _C_CTYPE_LOWER:
+ _C_CTYPE_PUNCT:
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isblank (int c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static inline int c_iscntrl (int c)
+{
+ switch (c) {
+ _C_CTYPE_CNTRL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isdigit (int c)
+{
+ switch (c) {
+ _C_CTYPE_DIGIT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isgraph (int c)
+{
+ switch (c) {
+ _C_CTYPE_DIGIT:
+ _C_CTYPE_LOWER:
+ _C_CTYPE_PUNCT:
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_islower (int c)
+{
+ switch (c) {
+ _C_CTYPE_LOWER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isprint (int c)
+{
+ switch (c) {
+ case ' ':
+ _C_CTYPE_DIGIT:
+ _C_CTYPE_LOWER:
+ _C_CTYPE_PUNCT:
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_ispunct (int c)
+{
+ switch (c) {
+ _C_CTYPE_PUNCT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isspace (int c)
+{
+ switch (c) {
+ case ' ': case '\t': case '\n': case '\v': case '\f': case '\r':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isupper (int c)
+{
+ switch (c) {
+ _C_CTYPE_UPPER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_isxdigit (int c)
+{
+ switch (c) {
+ _C_CTYPE_DIGIT:
+ _C_CTYPE_A_THRU_F:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline int c_tolower (int c)
+{
+ switch (c) {
+ _C_CTYPE_UPPER:
+ return c - 'A' + 'a';
+ default:
+ return c;
+ }
+}
+
+static inline int c_toupper (int c)
+{
+ switch (c) {
+ _C_CTYPE_LOWER:
+ return c - 'a' + 'A';
+ default:
+ return c;
+ }
+}
+
+#endif /* UTIL_LINUX_CCTYPE_H */
diff --git a/src/utils/include/closestream.h b/src/utils/include/closestream.h
new file mode 100644
index 0000000..41afbe2
--- /dev/null
+++ b/src/utils/include/closestream.h
@@ -0,0 +1,110 @@
+#ifndef UTIL_LINUX_CLOSESTREAM_H
+#define UTIL_LINUX_CLOSESTREAM_H
+
+#include <stdio.h>
+#ifdef HAVE_STDIO_EXT_H
+#include <stdio_ext.h>
+#endif
+#include <unistd.h>
+
+#include "c.h"
+#include "nls.h"
+
+#ifndef CLOSE_EXIT_CODE
+# define CLOSE_EXIT_CODE EXIT_FAILURE
+#endif
+
+static inline int
+close_stream(FILE * stream)
+{
+#ifdef HAVE___FPENDING
+ const int some_pending = (__fpending(stream) != 0);
+#endif
+ const int prev_fail = (ferror(stream) != 0);
+ const int fclose_fail = (fclose(stream) != 0);
+
+ if (prev_fail || (fclose_fail && (
+#ifdef HAVE___FPENDING
+ some_pending ||
+#endif
+ errno != EBADF))) {
+ if (!fclose_fail && !(errno == EPIPE))
+ errno = 0;
+ return EOF;
+ }
+ return 0;
+}
+
+static inline int
+flush_standard_stream(FILE *stream)
+{
+ int fd;
+
+ errno = 0;
+
+ if (ferror(stream) != 0 || fflush(stream) != 0)
+ goto error;
+
+ /*
+ * Calling fflush is not sufficient on some filesystems
+ * like e.g. NFS, which may defer the actual flush until
+ * close. Calling fsync would help solve this, but would
+ * probably result in a performance hit. Thus, we work
+ * around this issue by calling close on a dup'd file
+ * descriptor from the stream.
+ */
+ if ((fd = fileno(stream)) < 0 || (fd = dup(fd)) < 0 || close(fd) != 0)
+ goto error;
+
+ return 0;
+error:
+ return (errno == EBADF) ? 0 : EOF;
+}
+
+/* Meant to be used atexit(close_stdout); */
+static inline void
+close_stdout(void)
+{
+ if (flush_standard_stream(stdout) != 0 && !(errno == EPIPE)) {
+ if (errno)
+ warn(_("write error"));
+ else
+ warnx(_("write error"));
+ _exit(CLOSE_EXIT_CODE);
+ }
+
+ if (flush_standard_stream(stderr) != 0)
+ _exit(CLOSE_EXIT_CODE);
+}
+
+static inline void
+close_stdout_atexit(void)
+{
+ /*
+ * Note that close stdout at exit disables ASAN to report memory leaks
+ */
+#if !defined(__SANITIZE_ADDRESS__)
+ atexit(close_stdout);
+#endif
+}
+
+#ifndef HAVE_FSYNC
+static inline int
+fsync(int fd __attribute__((__unused__)))
+{
+ return 0;
+}
+#endif
+
+static inline int
+close_fd(int fd)
+{
+ const int fsync_fail = (fsync(fd) != 0);
+ const int close_fail = (close(fd) != 0);
+
+ if (fsync_fail || close_fail)
+ return EOF;
+ return 0;
+}
+
+#endif /* UTIL_LINUX_CLOSESTREAM_H */
diff --git a/src/utils/include/color-names.h b/src/utils/include/color-names.h
new file mode 100644
index 0000000..42f6f8f
--- /dev/null
+++ b/src/utils/include/color-names.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012-2015 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_COLOR_NAMES_H
+#define UTIL_LINUX_COLOR_NAMES_H
+
+#define UL_COLOR_RESET "\033[0m"
+#define UL_COLOR_BOLD "\033[1m"
+#define UL_COLOR_HALFBRIGHT "\033[2m"
+#define UL_COLOR_UNDERSCORE "\033[4m"
+#define UL_COLOR_BLINK "\033[5m"
+#define UL_COLOR_REVERSE "\033[7m"
+
+/* Standard colors */
+#define UL_COLOR_BLACK "\033[30m"
+#define UL_COLOR_RED "\033[31m"
+#define UL_COLOR_GREEN "\033[32m"
+#define UL_COLOR_BROWN "\033[33m" /* well, brown */
+#define UL_COLOR_BLUE "\033[34m"
+#define UL_COLOR_MAGENTA "\033[35m"
+#define UL_COLOR_CYAN "\033[36m"
+#define UL_COLOR_GRAY "\033[37m"
+
+/* Bold variants */
+#define UL_COLOR_DARK_GRAY "\033[1;30m"
+#define UL_COLOR_BOLD_RED "\033[1;31m"
+#define UL_COLOR_BOLD_GREEN "\033[1;32m"
+#define UL_COLOR_BOLD_YELLOW "\033[1;33m"
+#define UL_COLOR_BOLD_BLUE "\033[1;34m"
+#define UL_COLOR_BOLD_MAGENTA "\033[1;35m"
+#define UL_COLOR_BOLD_CYAN "\033[1;36m"
+
+#define UL_COLOR_WHITE "\033[1;37m"
+
+
+/* maximal length of human readable name of ESC seq. */
+#define UL_COLORNAME_MAXSZ 32
+
+extern const char *color_sequence_from_colorname(const char *str);
+
+#endif /* UTIL_LINUX_COLOR_NAMES_H */
diff --git a/src/utils/include/colors.h b/src/utils/include/colors.h
new file mode 100644
index 0000000..d4ae4e4
--- /dev/null
+++ b/src/utils/include/colors.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_COLORS_H
+#define UTIL_LINUX_COLORS_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "color-names.h"
+
+/* --color[=WHEN] */
+enum colortmode {
+ UL_COLORMODE_AUTO = 0,
+ UL_COLORMODE_NEVER,
+ UL_COLORMODE_ALWAYS,
+ UL_COLORMODE_UNDEF,
+
+ __UL_NCOLORMODES /* last */
+};
+
+#ifdef USE_COLORS_BY_DEFAULT
+# define USAGE_COLORS_DEFAULT _("colors are enabled by default")
+#else
+# define USAGE_COLORS_DEFAULT _("colors are disabled by default")
+#endif
+
+extern int colormode_from_string(const char *str);
+extern int colormode_or_err(const char *str, const char *errmsg);
+
+/* Initialize the global variable UL_COLOR_TERM_OK */
+extern int colors_init(int mode, const char *util_name);
+
+/* Returns 1 or 0 */
+extern int colors_wanted(void);
+
+/* Returns UL_COLORMODE_* */
+extern int colors_mode(void);
+
+/* temporary enable/disable colors */
+extern void colors_off(void);
+extern void colors_on(void);
+
+
+/* Set the color */
+extern void color_fenable(const char *seq, FILE *f);
+
+extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f);
+extern const char *color_scheme_get_sequence(const char *name, const char *dflt);
+
+static inline void color_enable(const char *seq)
+{
+ color_fenable(seq, stdout);
+}
+
+static inline void color_scheme_enable(const char *name, const char *dflt)
+{
+ color_scheme_fenable(name, dflt, stdout);
+}
+
+/* Reset colors to default */
+extern void color_fdisable(FILE *f);
+
+static inline void color_disable(void)
+{
+ color_fdisable(stdout);
+}
+
+#endif /* UTIL_LINUX_COLORS_H */
diff --git a/src/utils/include/cpuset.h b/src/utils/include/cpuset.h
new file mode 100644
index 0000000..5a531bf
--- /dev/null
+++ b/src/utils/include/cpuset.h
@@ -0,0 +1,99 @@
+/*
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_CPUSET_H
+#define UTIL_LINUX_CPUSET_H
+
+#include <sched.h>
+
+/*
+ * Fallback for old or obscure libcs without dynamically allocated cpusets
+ *
+ * The following macros are based on code from glibc.
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+#if !HAVE_DECL_CPU_ALLOC
+
+# define CPU_ZERO_S(setsize, cpusetp) \
+ do { \
+ size_t __i; \
+ size_t __imax = (setsize) / sizeof (__cpu_mask); \
+ __cpu_mask *__bits = (cpusetp)->__bits; \
+ for (__i = 0; __i < __imax; ++__i) \
+ __bits[__i] = 0; \
+ } while (0)
+
+# define CPU_SET_S(cpu, setsize, cpusetp) \
+ ({ size_t __cpu = (cpu); \
+ __cpu < 8 * (setsize) \
+ ? (((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \
+ |= __CPUMASK (__cpu)) \
+ : 0; })
+
+# define CPU_ISSET_S(cpu, setsize, cpusetp) \
+ ({ size_t __cpu = (cpu); \
+ __cpu < 8 * (setsize) \
+ ? ((((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \
+ & __CPUMASK (__cpu))) != 0 \
+ : 0; })
+
+# define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \
+ ({ __cpu_mask *__arr1 = (cpusetp1)->__bits; \
+ __cpu_mask *__arr2 = (cpusetp2)->__bits; \
+ size_t __imax = (setsize) / sizeof (__cpu_mask); \
+ size_t __i; \
+ for (__i = 0; __i < __imax; ++__i) \
+ if (__arr1[__i] != __arr2[__i]) \
+ break; \
+ __i == __imax; })
+
+extern int __cpuset_count_s(size_t setsize, const cpu_set_t *set);
+# define CPU_COUNT_S(setsize, cpusetp) __cpuset_count_s(setsize, cpusetp)
+
+# define CPU_ALLOC_SIZE(count) \
+ ((((count) + __NCPUBITS - 1) / __NCPUBITS) * sizeof (__cpu_mask))
+# define CPU_ALLOC(count) (malloc(CPU_ALLOC_SIZE(count)))
+# define CPU_FREE(cpuset) (free(cpuset))
+
+#endif /* !HAVE_DECL_CPU_ALLOC */
+
+
+#define cpuset_nbits(setsize) (8 * (setsize))
+
+/*
+ * The @idx parameter returns an index of the first mask from @ary array where
+ * the @cpu is set.
+ *
+ * Returns: 0 if found, otherwise 1.
+ */
+static inline int cpuset_ary_isset(size_t cpu, cpu_set_t **ary, size_t nmemb,
+ size_t setsize, size_t *idx)
+{
+ size_t i;
+
+ for (i = 0; i < nmemb; i++) {
+ if (CPU_ISSET_S(cpu, setsize, ary[i])) {
+ *idx = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+extern int get_max_number_of_cpus(void);
+
+extern cpu_set_t *cpuset_alloc(int ncpus, size_t *setsize, size_t *nbits);
+extern void cpuset_free(cpu_set_t *set);
+
+extern char *cpulist_create(char *str, size_t len, cpu_set_t *set, size_t setsize);
+extern int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail);
+
+extern char *cpumask_create(char *str, size_t len, cpu_set_t *set, size_t setsize);
+extern int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize);
+
+#endif /* UTIL_LINUX_CPUSET_H */
diff --git a/src/utils/include/crc32.h b/src/utils/include/crc32.h
new file mode 100644
index 0000000..2551f50
--- /dev/null
+++ b/src/utils/include/crc32.h
@@ -0,0 +1,12 @@
+#ifndef UL_NG_CRC32_H
+#define UL_NG_CRC32_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern uint32_t ul_crc32(uint32_t seed, const unsigned char *buf, size_t len);
+extern uint32_t ul_crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len);
+
+#endif
+
diff --git a/src/utils/include/crc32c.h b/src/utils/include/crc32c.h
new file mode 100644
index 0000000..1c50839
--- /dev/null
+++ b/src/utils/include/crc32c.h
@@ -0,0 +1,9 @@
+#ifndef UL_NG_CRC32C_H
+#define UL_NG_CRC32C_H
+
+#include <sys/types.h>
+#include <stdint.h>
+
+extern uint32_t crc32c(uint32_t crc, const void *buf, size_t size);
+
+#endif /* UL_NG_CRC32C_H */
diff --git a/src/utils/include/debug.h b/src/utils/include/debug.h
new file mode 100644
index 0000000..39c21d5
--- /dev/null
+++ b/src/utils/include/debug.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_DEBUG_H
+#define UTIL_LINUX_DEBUG_H
+
+
+/*
+ * util-linux debug macros
+ *
+ * The debug stuff is based on <name>_debug_mask that controls what outputs is
+ * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable
+ *
+ * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set
+ * to the mask (this flag is required). The <PREFIX> is usually library API
+ * prefix (e.g. MNT_) or program name (e.g. CFDISK_)
+ *
+ * In the code is possible to use
+ *
+ * DBG(FOO, ul_debug("this is output for foo"));
+ *
+ * where for the FOO has to be defined <PREFIX>_DEBUG_FOO.
+ *
+ * It's possible to initialize the mask by comma delimited strings with
+ * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is
+ * necessary to define mask names array. This functionality is optional.
+ *
+ * It's strongly recommended to use UL_* macros to define/declare/use
+ * the debug stuff.
+ *
+ * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug
+ * or libmount/src/init.c: mnt_init_debug() for library debug
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+struct ul_debug_maskname {
+ const char *name;
+ int mask;
+ const char *help;
+};
+#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }}
+#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[]
+#define UL_DEBUG_MASKNAMES(m) m ## _masknames
+
+#define UL_DEBUG_MASK(m) m ## _debug_mask
+#define UL_DEBUG_DEFINE_MASK(m) int UL_DEBUG_MASK(m)
+#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m)
+
+/*
+ * Internal mask flags (above 0xffffff)
+ */
+#define __UL_DEBUG_FL_NOADDR (1 << 24) /* Don't print object address */
+
+
+/* l - library name, p - flag prefix, m - flag postfix, x - function */
+#define __UL_DBG(l, p, m, x) \
+ do { \
+ if ((p ## m) & l ## _debug_mask) { \
+ fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \
+ x; \
+ } \
+ } while (0)
+
+#define __UL_DBG_CALL(l, p, m, x) \
+ do { \
+ if ((p ## m) & l ## _debug_mask) { \
+ x; \
+ } \
+ } while (0)
+
+#define __UL_DBG_FLUSH(l, p) \
+ do { \
+ if (l ## _debug_mask && \
+ l ## _debug_mask != p ## INIT) { \
+ fflush(stderr); \
+ } \
+ } while (0)
+
+#define __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, str) \
+ do { \
+ if (lib ## _debug_mask & pref ## INIT) \
+ ; \
+ else if (!mask && str) { \
+ lib ## _debug_mask = ul_debug_parse_mask(lib ## _masknames, str); \
+ } else \
+ lib ## _debug_mask = mask; \
+ if (lib ## _debug_mask) { \
+ if (getuid() != geteuid() || getgid() != getegid()) { \
+ lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \
+ fprintf(stderr, "%d: %s: don't print memory addresses (SUID executable).\n", getpid(), # lib); \
+ } \
+ } \
+ lib ## _debug_mask |= pref ## INIT; \
+ } while (0)
+
+
+#define __UL_INIT_DEBUG_FROM_ENV(lib, pref, mask, env) \
+ do { \
+ const char *envstr = mask ? NULL : getenv(# env); \
+ __UL_INIT_DEBUG_FROM_STRING(lib, pref, mask, envstr); \
+ } while (0)
+
+
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+ul_debug(const char *mesg, ...)
+{
+ va_list ap;
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+static inline int ul_debug_parse_mask(
+ const struct ul_debug_maskname flagnames[],
+ const char *mask)
+{
+ int res;
+ char *ptr;
+
+ /* let's check for a numeric mask first */
+ res = strtoul(mask, &ptr, 0);
+
+ /* perhaps it's a comma-separated string? */
+ if (ptr && *ptr && flagnames && flagnames[0].name) {
+ char *msbuf, *ms, *name;
+ res = 0;
+
+ ms = msbuf = strdup(mask);
+ if (!ms)
+ return res;
+
+ while ((name = strtok_r(ms, ",", &ptr))) {
+ const struct ul_debug_maskname *d;
+ ms = ptr;
+
+ for (d = flagnames; d && d->name; d++) {
+ if (strcmp(name, d->name) == 0) {
+ res |= d->mask;
+ break;
+ }
+ }
+ /* nothing else we can do by OR-ing the mask */
+ if (res == 0xffff)
+ break;
+ }
+ free(msbuf);
+ } else if (ptr && strcmp(ptr, "all") == 0)
+ res = 0xffff;
+
+ return res;
+}
+
+static inline void ul_debug_print_masks(
+ const char *env,
+ const struct ul_debug_maskname flagnames[])
+{
+ const struct ul_debug_maskname *d;
+
+ if (!flagnames)
+ return;
+
+ fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n",
+ env);
+ for (d = flagnames; d && d->name; d++) {
+ if (!d->help)
+ continue;
+ fprintf(stderr, " %-8s [0x%04x] : %s\n",
+ d->name, d->mask, d->help);
+ }
+}
+
+#endif /* UTIL_LINUX_DEBUG_H */
diff --git a/src/utils/include/debugobj.h b/src/utils/include/debugobj.h
new file mode 100644
index 0000000..73b70b8
--- /dev/null
+++ b/src/utils/include/debugobj.h
@@ -0,0 +1,22 @@
+#ifndef UTIL_LINUX_DEBUGOBJ_H
+#define UTIL_LINUX_DEBUGOBJ_H
+
+/*
+ * Include *after* debug.h and after UL_DEBUG_CURRENT_MASK define.
+ */
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+ul_debugobj(const void *handler, const char *mesg, ...)
+{
+ va_list ap;
+
+ if (handler && !(UL_DEBUG_CURRENT_MASK & __UL_DEBUG_FL_NOADDR))
+ fprintf(stderr, "[%p]: ", handler);
+
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+#endif /* UTIL_LINUX_DEBUGOBJ_H */
diff --git a/src/utils/include/encode.h b/src/utils/include/encode.h
new file mode 100644
index 0000000..b259ab5
--- /dev/null
+++ b/src/utils/include/encode.h
@@ -0,0 +1,14 @@
+#ifndef UTIL_LINUX_ENCODE_H
+#define UTIL_LINUX_ENCODE_H
+
+extern size_t ul_encode_to_utf8(int enc, unsigned char *dest, size_t len,
+ const unsigned char *src, size_t count)
+ __attribute__((nonnull));
+
+enum {
+ UL_ENCODE_UTF16BE = 0,
+ UL_ENCODE_UTF16LE,
+ UL_ENCODE_LATIN1
+};
+
+#endif
diff --git a/src/utils/include/env.h b/src/utils/include/env.h
new file mode 100644
index 0000000..c2caecb
--- /dev/null
+++ b/src/utils/include/env.h
@@ -0,0 +1,35 @@
+#ifndef UTIL_LINUX_ENV_H
+#define UTIL_LINUX_ENV_H
+
+#include "c.h"
+#include "nls.h"
+
+struct ul_env_list;
+
+extern void sanitize_env(void);
+extern void __sanitize_env(struct ul_env_list **org);
+
+extern int env_list_setenv(struct ul_env_list *ls);
+extern void env_list_free(struct ul_env_list *ls);
+
+extern char *safe_getenv(const char *arg);
+
+
+#ifndef XSETENV_EXIT_CODE
+# define XSETENV_EXIT_CODE EXIT_FAILURE
+#endif
+
+static inline void xsetenv(char const *name, char const *val, int overwrite)
+{
+ if (setenv(name, val, overwrite) != 0)
+ err(XSETENV_EXIT_CODE, _("failed to set the %s environment variable"), name);
+}
+
+static inline int remote_entry(char **argv, int remove, int last)
+{
+ memmove(argv + remove, argv + remove + 1, sizeof(char *) * (last - remove));
+ return last - 1;
+}
+
+#endif /* UTIL_LINUX_ENV_H */
+
diff --git a/src/utils/include/exec_shell.h b/src/utils/include/exec_shell.h
new file mode 100644
index 0000000..04aa089
--- /dev/null
+++ b/src/utils/include/exec_shell.h
@@ -0,0 +1,6 @@
+#ifndef UTIL_LINUX_EXEC_SHELL_H
+#define UTIL_LINUX_EXEC_SHELL_H
+
+extern void exec_shell(void) __attribute__((__noreturn__));
+
+#endif /* UTIL_LINUX_EXEC_SHELL_H */
diff --git a/src/utils/include/exitcodes.h b/src/utils/include/exitcodes.h
new file mode 100644
index 0000000..f28f68e
--- /dev/null
+++ b/src/utils/include/exitcodes.h
@@ -0,0 +1,25 @@
+#ifndef UTIL_LINUX_EXITCODES_H
+#define UTIL_LINUX_EXITCODES_H
+/*
+ * BE CAREFUL
+ *
+ * These exit codes are part of the official interface for mount,
+ * fsck, mkfs, etc. wrappers.
+ */
+
+/* Exit codes used by mkfs-type programs */
+#define MKFS_EX_OK 0 /* No errors */
+#define MKFS_EX_ERROR 8 /* Operational error */
+#define MKFS_EX_USAGE 16 /* Usage or syntax error */
+
+/* Exit codes used by fsck-type programs */
+#define FSCK_EX_OK 0 /* No errors */
+#define FSCK_EX_NONDESTRUCT 1 /* File system errors corrected */
+#define FSCK_EX_REBOOT 2 /* System should be rebooted */
+#define FSCK_EX_DESTRUCT FSCK_EX_REBOOT /* Alias */
+#define FSCK_EX_UNCORRECTED 4 /* File system errors left uncorrected */
+#define FSCK_EX_ERROR 8 /* Operational error */
+#define FSCK_EX_USAGE 16 /* Usage or syntax error */
+#define FSCK_EX_LIBRARY 128 /* Shared library error */
+
+#endif /* UTIL_LINUX_EXITCODES_H */
diff --git a/src/utils/include/fileutils.h b/src/utils/include/fileutils.h
new file mode 100644
index 0000000..479ad15
--- /dev/null
+++ b/src/utils/include/fileutils.h
@@ -0,0 +1,77 @@
+#ifndef UTIL_LINUX_FILEUTILS
+#define UTIL_LINUX_FILEUTILS
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "c.h"
+
+extern int mkstemp_cloexec(char *template);
+
+extern int xmkstemp(char **tmpname, const char *dir, const char *prefix);
+
+static inline FILE *xfmkstemp(char **tmpname, const char *dir, const char *prefix)
+{
+ int fd;
+ FILE *ret;
+
+ fd = xmkstemp(tmpname, dir, prefix);
+ if (fd == -1)
+ return NULL;
+
+ if (!(ret = fdopen(fd, "w+" UL_CLOEXECSTR))) {
+ close(fd);
+ return NULL;
+ }
+ return ret;
+}
+
+#ifdef HAVE_OPENAT
+static inline FILE *fopen_at(int dir, const char *filename,
+ int flags, const char *mode)
+{
+ int fd = openat(dir, filename, flags);
+ if (fd < 0)
+ return NULL;
+
+ return fdopen(fd, mode);
+}
+#endif
+
+static inline int is_same_inode(const int fd, const struct stat *st)
+{
+ struct stat f;
+
+ if (fstat(fd, &f) < 0)
+ return 0;
+ else if (f.st_dev != st->st_dev || f.st_ino != st->st_ino)
+ return 0;
+ return 1;
+}
+
+extern int dup_fd_cloexec(int oldfd, int lowfd);
+extern int get_fd_tabsize(void);
+
+extern int mkdir_p(const char *path, mode_t mode);
+extern char *stripoff_last_component(char *path);
+
+/* This is readdir()-like function, but skips "." and ".." directory entries */
+static inline struct dirent *xreaddir(DIR *dp)
+{
+ struct dirent *d;
+
+ while ((d = readdir(dp))) {
+ if (!strcmp(d->d_name, ".") ||
+ !strcmp(d->d_name, ".."))
+ continue;
+ break;
+ }
+ return d;
+}
+
+extern void close_all_fds(const int exclude[], size_t exsz);
+
+#endif /* UTIL_LINUX_FILEUTILS */
diff --git a/src/utils/include/fuzz.h b/src/utils/include/fuzz.h
new file mode 100644
index 0000000..1b0dbd2
--- /dev/null
+++ b/src/utils/include/fuzz.h
@@ -0,0 +1,9 @@
+#ifndef UTIL_LINUX_FUZZ_H
+#define UTIL_LINUX_FUZZ_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+#endif /* UTIL_LINUX_FUZZ_H */
diff --git a/src/utils/include/idcache.h b/src/utils/include/idcache.h
new file mode 100644
index 0000000..912edd5
--- /dev/null
+++ b/src/utils/include/idcache.h
@@ -0,0 +1,28 @@
+#ifndef UTIL_LINUX_IDCACHE_H
+#define UTIL_LINUX_IDCACHE_H
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#define IDCACHE_FLAGS_NAMELEN (1 << 1)
+
+struct identry {
+ unsigned long int id;
+ char *name;
+ struct identry *next;
+};
+
+struct idcache {
+ struct identry *ent; /* first entry */
+ int width; /* name width */
+};
+
+
+extern struct idcache *new_idcache(void);
+extern void add_gid(struct idcache *cache, unsigned long int id);
+extern void add_uid(struct idcache *cache, unsigned long int id);
+
+extern void free_idcache(struct idcache *ic);
+extern struct identry *get_id(struct idcache *ic, unsigned long int id);
+
+#endif /* UTIL_LINUX_IDCACHE_H */
diff --git a/src/utils/include/ismounted.h b/src/utils/include/ismounted.h
new file mode 100644
index 0000000..57918cb
--- /dev/null
+++ b/src/utils/include/ismounted.h
@@ -0,0 +1,14 @@
+#ifndef IS_MOUNTED_H
+#define IS_MOUNTED_H
+
+#define MF_MOUNTED 1
+#define MF_ISROOT 2
+#define MF_READONLY 4
+#define MF_SWAP 8
+#define MF_BUSY 16
+
+extern int is_mounted(const char *file);
+extern int check_mount_point(const char *device, int *mount_flags,
+ char *mtpt, int mtlen);
+
+#endif /* IS_MOUNTED_H */
diff --git a/src/utils/include/iso9660.h b/src/utils/include/iso9660.h
new file mode 100644
index 0000000..73decd9
--- /dev/null
+++ b/src/utils/include/iso9660.h
@@ -0,0 +1,58 @@
+#ifndef UTIL_LINUX_ISO_H
+#define UTIL_LINUX_ISO_H
+
+#include <stdbool.h>
+
+#include "c.h"
+
+static inline int isonum_721(unsigned char *p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8));
+}
+
+static inline int isonum_722(unsigned char *p)
+{
+ return ((p[1] & 0xff)
+ | ((p[0] & 0xff) << 8));
+}
+
+static inline int isonum_723(unsigned char *p, bool check_match)
+{
+ int le = isonum_721(p);
+ int be = isonum_722(p + 2);
+
+ if (check_match && le != be)
+ /* translation is useless */
+ warnx("723error: le=%d be=%d", le, be);
+ return (le);
+}
+
+static inline int isonum_731(unsigned char *p)
+{
+ return ((p[0] & 0xff)
+ | ((p[1] & 0xff) << 8)
+ | ((p[2] & 0xff) << 16)
+ | ((p[3] & 0xff) << 24));
+}
+
+static inline int isonum_732(unsigned char *p)
+{
+ return ((p[3] & 0xff)
+ | ((p[2] & 0xff) << 8)
+ | ((p[1] & 0xff) << 16)
+ | ((p[0] & 0xff) << 24));
+}
+
+static inline int isonum_733(unsigned char *p, bool check_match)
+{
+ int le = isonum_731(p);
+ int be = isonum_732(p + 4);
+
+ if (check_match && le != be)
+ /* translation is useless */
+ warnx("733error: le=%d be=%d", le, be);
+ return(le);
+}
+
+#endif
diff --git a/src/utils/include/linux_version.h b/src/utils/include/linux_version.h
new file mode 100644
index 0000000..a6a1e99
--- /dev/null
+++ b/src/utils/include/linux_version.h
@@ -0,0 +1,14 @@
+#ifndef LINUX_VERSION_H
+#define LINUX_VERSION_H
+
+#ifdef HAVE_LINUX_VERSION_H
+# include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+int get_linux_version(void);
+
+#endif /* LINUX_VERSION_H */
diff --git a/src/utils/include/list.h b/src/utils/include/list.h
new file mode 100644
index 0000000..96c84e5
--- /dev/null
+++ b/src/utils/include/list.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 1999-2008 by Theodore Ts'o
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * (based on list.h from e2fsprogs)
+ * Merge sort based on kernel's implementation.
+ */
+
+#ifndef UTIL_LINUX_LIST_H
+#define UTIL_LINUX_LIST_H
+
+#include "c.h"
+
+/* TODO: use AC_C_INLINE */
+#ifdef __GNUC__
+#define _INLINE_ static __inline__
+#else /* For Watcom C */
+#define _INLINE_ static inline
+#endif
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_add(struct list_head * add,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = add;
+ add->next = next;
+ add->prev = prev;
+ prev->next = add;
+}
+
+/**
+ * list_add - add a new entry
+ * @add: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+_INLINE_ void list_add(struct list_head *add, struct list_head *head)
+{
+ __list_add(add, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @add: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head)
+{
+ __list_add(add, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+_INLINE_ void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ *
+ * list_empty() on @entry does not return true after this, @entry is
+ * in an undefined state.
+ */
+_INLINE_ void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+_INLINE_ void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+_INLINE_ int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_entry_is_last - tests whether is entry last in the list
+ * @entry: the entry to test.
+ * @head: the list to test.
+ */
+_INLINE_ int list_entry_is_last(struct list_head *entry, struct list_head *head)
+{
+ return head->prev == entry;
+}
+
+/**
+ * list_entry_is_first - tests whether is entry first in the list
+ * @entry: the entry to test.
+ * @head: the list to test.
+ */
+_INLINE_ int list_entry_is_first(struct list_head *entry, struct list_head *head)
+{
+ return head->next == entry;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+_INLINE_ void list_splice(struct list_head *list, struct list_head *head)
+{
+ struct list_head *first = list->next;
+
+ if (first != list) {
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define list_first_entry(head, type, member) \
+ ((head) && (head)->next != (head) ? list_entry((head)->next, type, member) : NULL)
+
+#define list_last_entry(head, type, member) \
+ ((head) && (head)->prev != (head) ? list_entry((head)->prev, type, member) : NULL)
+
+/**
+ * list_for_each - iterate over elements in a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_backwardly - iterate over elements in a list in reverse
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_backwardly(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over elements in a list, but don't dereference
+ * pos after the body is done (in case it is freed)
+ * @pos: the &struct list_head to use as a loop counter.
+ * @pnext: the &struct list_head to use as a pointer to the next item.
+ * @head: the head for your list (not included in iteration).
+ */
+#define list_for_each_safe(pos, pnext, head) \
+ for (pos = (head)->next, pnext = pos->next; pos != (head); \
+ pos = pnext, pnext = pos->next)
+
+_INLINE_ size_t list_count_entries(struct list_head *head)
+{
+ struct list_head *pos;
+ size_t ct = 0;
+
+ list_for_each(pos, head)
+ ct++;
+
+ return ct;
+}
+
+#define MAX_LIST_LENGTH_BITS 20
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+_INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a,
+ struct list_head *b,
+ void *data),
+ void *data,
+ struct list_head *a, struct list_head *b)
+{
+ struct list_head head, *tail = &head;
+
+ while (a && b) {
+ /* if equal, take 'a' -- important for sort stability */
+ if ((*cmp)(a, b, data) <= 0) {
+ tail->next = a;
+ a = a->next;
+ } else {
+ tail->next = b;
+ b = b->next;
+ }
+ tail = tail->next;
+ }
+ tail->next = a ? a : b;
+ return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure. This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+_INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a,
+ struct list_head *b,
+ void *data),
+ void *data,
+ struct list_head *head,
+ struct list_head *a, struct list_head *b)
+{
+ struct list_head *tail = head;
+
+ while (a && b) {
+ /* if equal, take 'a' -- important for sort stability */
+ if ((*cmp)(a, b, data) <= 0) {
+ tail->next = a;
+ a->prev = tail;
+ a = a->next;
+ } else {
+ tail->next = b;
+ b->prev = tail;
+ b = b->next;
+ }
+ tail = tail->next;
+ }
+ tail->next = a ? a : b;
+
+ do {
+ /*
+ * In worst cases this loop may run many iterations.
+ * Continue callbacks to the client even though no
+ * element comparison is needed, so the client's cmp()
+ * routine can invoke cond_resched() periodically.
+ */
+ (*cmp)(tail->next, tail->next, data);
+
+ tail->next->prev = tail;
+ tail = tail->next;
+ } while (tail->next);
+
+ tail->next = head;
+ head->prev = tail;
+}
+
+
+/**
+ * list_sort - sort a list
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+_INLINE_ void list_sort(struct list_head *head,
+ int (*cmp)(struct list_head *a,
+ struct list_head *b,
+ void *data),
+ void *data)
+{
+ struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+ -- last slot is a sentinel */
+ size_t lev; /* index into part[] */
+ size_t max_lev = 0;
+ struct list_head *list;
+
+ if (list_empty(head))
+ return;
+
+ memset(part, 0, sizeof(part));
+
+ head->prev->next = NULL;
+ list = head->next;
+
+ while (list) {
+ struct list_head *cur = list;
+ list = list->next;
+ cur->next = NULL;
+
+ for (lev = 0; part[lev]; lev++) {
+ cur = merge(cmp, data, part[lev], cur);
+ part[lev] = NULL;
+ }
+ if (lev > max_lev) {
+ /* list passed to list_sort() too long for efficiency */
+ if (lev >= ARRAY_SIZE(part) - 1)
+ lev--;
+ max_lev = lev;
+ }
+ part[lev] = cur;
+ }
+
+ for (lev = 0; lev < max_lev; lev++)
+ if (part[lev])
+ list = merge(cmp, data, part[lev], list);
+
+ merge_and_restore_back_links(cmp, data, head, part[max_lev], list);
+}
+
+#undef _INLINE_
+
+#endif /* UTIL_LINUX_LIST_H */
diff --git a/src/utils/include/loopdev.h b/src/utils/include/loopdev.h
new file mode 100644
index 0000000..0221e6b
--- /dev/null
+++ b/src/utils/include/loopdev.h
@@ -0,0 +1,222 @@
+#ifndef UTIL_LINUX_LOOPDEV_H
+#define UTIL_LINUX_LOOPDEV_H
+
+#include "sysfs.h"
+
+/*
+ * loop_info.lo_encrypt_type
+ */
+#define LO_CRYPT_NONE 0
+#define LO_CRYPT_XOR 1
+#define LO_CRYPT_DES 2
+#define LO_CRYPT_CRYPTOAPI 18
+
+/*
+ * loop_info.lo_file_fmt_type
+ */
+#define LO_FILE_FMT_RAW 0
+#define LO_FILE_FMT_QCOW 1
+#define LO_FILE_FMT_VDI 2
+#define LO_FILE_FMT_VMDK 3
+
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+/*
+ * Obsolete (kernel < 2.6)
+ *
+ * #define LOOP_SET_STATUS 0x4C02
+ * #define LOOP_GET_STATUS 0x4C03
+ */
+#define LOOP_SET_STATUS64 0x4C04
+#define LOOP_GET_STATUS64 0x4C05
+/* #define LOOP_CHANGE_FD 0x4C06 */
+#define LOOP_SET_CAPACITY 0x4C07
+#define LOOP_SET_DIRECT_IO 0x4C08
+#define LOOP_SET_BLOCK_SIZE 0x4C09
+
+/* /dev/loop-control interface */
+#ifndef LOOP_CTL_ADD
+# define LOOP_CTL_ADD 0x4C80
+# define LOOP_CTL_REMOVE 0x4C81
+# define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
+/*
+ * loop_info.lo_flags
+ */
+enum {
+ LO_FLAGS_READ_ONLY = 1,
+ LO_FLAGS_USE_AOPS = 2,
+ LO_FLAGS_AUTOCLEAR = 4, /* kernel >= 2.6.25 */
+ LO_FLAGS_PARTSCAN = 8, /* kernel >= 3.2 */
+ LO_FLAGS_DIRECT_IO = 16, /* kernel >= 4.2 */
+};
+
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+
+/*
+ * Linux LOOP_{SET,GET}_STATUS64 ioctl struct
+ */
+struct loop_info64 {
+ uint64_t lo_device;
+ uint64_t lo_inode;
+ uint64_t lo_rdevice;
+ uint64_t lo_offset;
+ uint64_t lo_sizelimit; /* bytes, 0 == max available */
+ uint32_t lo_number;
+ uint32_t lo_encrypt_type;
+ uint32_t lo_encrypt_key_size;
+ uint32_t lo_flags;
+ uint8_t lo_file_name[LO_NAME_SIZE];
+ uint8_t lo_crypt_name[LO_NAME_SIZE];
+ uint8_t lo_encrypt_key[LO_KEY_SIZE];
+ uint64_t lo_init[2];
+ uint32_t lo_file_fmt_type;
+};
+
+#define LOOPDEV_MAJOR XLOOP_MAJOR /* loop major number */
+#define LOOPDEV_DEFAULT_NNODES CONFIG_BLK_DEV_XLOOP_MIN_COUNT /* default number of loop devices */
+
+struct loopdev_iter {
+ FILE *proc; /* /proc/partitions */
+ DIR *sysblock; /* /sys/block */
+ int ncur; /* current position */
+ int *minors; /* ary of minor numbers (when scan whole /dev) */
+ int nminors; /* number of items in *minors */
+ int ct_perm; /* count permission problems */
+ int ct_succ; /* count number of detected devices */
+
+ unsigned int done:1; /* scanning done */
+ unsigned int default_check:1;/* check first LOOPDEV_NLOOPS */
+ int flags; /* LOOPITER_FL_* flags */
+};
+
+enum {
+ LOOPITER_FL_FREE = (1 << 0),
+ LOOPITER_FL_USED = (1 << 1)
+};
+
+/*
+ * handler for work with loop devices
+ */
+struct loopdev_cxt {
+ char device[128]; /* device path (e.g. /dev/loop<N>) */
+ char *filename; /* backing file for loopcxt_set_... */
+ int fd; /* open(/dev/looo<N>) */
+ int mode; /* fd mode O_{RDONLY,RDWR} */
+ uint64_t blocksize; /* used by loopcxt_setup_device() */
+
+ int flags; /* LOOPDEV_FL_* flags */
+ unsigned int has_info:1; /* .info contains data */
+ unsigned int extra_check:1; /* unusual stuff for iterator */
+ unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */
+ unsigned int control_ok:1; /* /dev/loop-control success */
+
+ struct path_cxt *sysfs; /* pointer to /sys/dev/block/<maj:min>/ */
+ struct loop_info64 info; /* for GET/SET ioctl */
+ struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */
+};
+
+#define UL_LOOPDEVCXT_EMPTY { .fd = -1 }
+
+/*
+ * loopdev_cxt.flags
+ */
+enum {
+ LOOPDEV_FL_RDONLY = (1 << 0), /* open(/dev/loop) mode; default */
+ LOOPDEV_FL_RDWR = (1 << 1), /* necessary for loop setup only */
+ LOOPDEV_FL_OFFSET = (1 << 4),
+ LOOPDEV_FL_NOSYSFS = (1 << 5),
+ LOOPDEV_FL_NOIOCTL = (1 << 6),
+ LOOPDEV_FL_DEVSUBDIR = (1 << 7),
+ LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */
+ LOOPDEV_FL_SIZELIMIT = (1 << 9)
+};
+
+/*
+ * High-level
+ */
+extern int loopmod_supports_partscan(void);
+
+extern int is_loopdev(const char *device);
+extern int loopdev_is_autoclear(const char *device);
+
+extern char *loopdev_get_backing_file(const char *device);
+extern int loopdev_is_used(const char *device, const char *filename,
+ uint64_t offset, uint64_t sizelimit, int flags);
+extern char *loopdev_find_by_backing_file(const char *filename,
+ uint64_t offset, uint64_t sizelimit, int flags);
+extern int loopcxt_find_unused(struct loopdev_cxt *lc);
+extern int loopdev_delete(const char *device);
+extern int loopdev_count_by_backing_file(const char *filename, char **loopdev);
+
+/*
+ * Low-level
+ */
+extern int loopcxt_init(struct loopdev_cxt *lc, int flags)
+ __attribute__ ((warn_unused_result));
+extern void loopcxt_deinit(struct loopdev_cxt *lc);
+
+extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
+ __attribute__ ((warn_unused_result));
+extern int loopcxt_has_device(struct loopdev_cxt *lc);
+extern int loopcxt_add_device(struct loopdev_cxt *lc);
+extern char *loopcxt_strdup_device(struct loopdev_cxt *lc);
+extern const char *loopcxt_get_device(struct loopdev_cxt *lc);
+extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc);
+
+extern int loopcxt_get_fd(struct loopdev_cxt *lc);
+extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode);
+
+extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags);
+extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc);
+extern int loopcxt_next(struct loopdev_cxt *lc);
+
+extern int loopcxt_setup_device(struct loopdev_cxt *lc);
+extern int loopcxt_delete_device(struct loopdev_cxt *lc);
+
+extern int loopcxt_ioctl_status(struct loopdev_cxt *lc);
+extern int loopcxt_ioctl_capacity(struct loopdev_cxt *lc);
+extern int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio);
+extern int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
+
+int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset);
+int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit);
+int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize);
+int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type);
+int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags);
+int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename);
+
+extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc);
+extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno);
+extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino);
+extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset);
+extern int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize);
+extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size);
+extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type);
+extern int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type);
+extern char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc);
+extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc);
+extern int loopcxt_is_autoclear(struct loopdev_cxt *lc);
+extern int loopcxt_is_readonly(struct loopdev_cxt *lc);
+extern int loopcxt_is_dio(struct loopdev_cxt *lc);
+extern int loopcxt_is_partscan(struct loopdev_cxt *lc);
+extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc,
+ const char *filename,
+ uint64_t offset, uint64_t sizelimit,
+ int flags);
+extern int loopcxt_find_overlap(struct loopdev_cxt *lc,
+ const char *filename,
+ uint64_t offset, uint64_t sizelimit);
+
+extern int loopcxt_is_used(struct loopdev_cxt *lc,
+ struct stat *st,
+ const char *backing_file,
+ uint64_t offset,
+ uint64_t sizelimit,
+ int flags);
+
+extern int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type);
+
+#endif /* UTIL_LINUX_LOOPDEV_H */
diff --git a/src/utils/include/mangle.h b/src/utils/include/mangle.h
new file mode 100644
index 0000000..08c66cb
--- /dev/null
+++ b/src/utils/include/mangle.h
@@ -0,0 +1,28 @@
+#ifndef UTIL_LINUX_MANGLE_H
+#define UTIL_LINUX_MANGLE_H
+
+/*
+ * Functions for \oct encoding used in mtab/fstab/swaps/etc.
+ */
+
+extern char *mangle(const char *s);
+
+extern void unmangle_to_buffer(const char *s, char *buf, size_t len);
+extern size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len);
+
+extern char *unmangle(const char *s, const char **end);
+
+static inline void unmangle_string(char *s)
+{
+ if (s)
+ unmangle_to_buffer(s, s, strlen(s) + 1);
+}
+
+static inline void unhexmangle_string(char *s)
+{
+ if (s)
+ unhexmangle_to_buffer(s, s, strlen(s) + 1);
+}
+
+#endif /* UTIL_LINUX_MANGLE_H */
+
diff --git a/src/utils/include/match.h b/src/utils/include/match.h
new file mode 100644
index 0000000..94440c2
--- /dev/null
+++ b/src/utils/include/match.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef UTIL_LINUX_MATCH_H
+#define UTIL_LINUX_MATCH_H
+
+extern int match_fstype(const char *type, const char *pattern);
+
+#endif /* UTIL_LINUX_MATCH_H */
diff --git a/src/utils/include/mbsalign.h b/src/utils/include/mbsalign.h
new file mode 100644
index 0000000..4f5add8
--- /dev/null
+++ b/src/utils/include/mbsalign.h
@@ -0,0 +1,66 @@
+/* Align/Truncate a string in a given screen width
+ Copyright (C) 2009-2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef UTIL_LINUX_MBSALIGN_H
+# define UTIL_LINUX_MBSALIGN_H
+# include <stddef.h>
+
+typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t;
+
+enum {
+ /* Use unibyte mode for invalid multibyte strings or
+ or when heap memory is exhausted. */
+ MBA_UNIBYTE_FALLBACK = 0x0001,
+
+#if 0 /* Other possible options. */
+ /* Skip invalid multibyte chars rather than failing */
+ MBA_IGNORE_INVALID = 0x0002,
+
+ /* Align multibyte strings using "figure space" (\u2007) */
+ MBA_USE_FIGURE_SPACE = 0x0004,
+
+ /* Don't add any padding */
+ MBA_TRUNCATE_ONLY = 0x0008,
+
+ /* Don't truncate */
+ MBA_PAD_ONLY = 0x0010,
+#endif
+};
+
+extern size_t mbs_truncate(char *str, size_t *width);
+
+extern size_t mbsalign (const char *src, char *dest,
+ size_t dest_size, size_t *width,
+ mbs_align_t align, int flags);
+
+extern size_t mbsalign_with_padding (const char *src, char *dest, size_t dest_size,
+ size_t *width, mbs_align_t align, int flags,
+ int padchar);
+
+extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz);
+extern size_t mbs_safe_width(const char *s);
+
+extern size_t mbs_nwidth(const char *buf, size_t bufsz);
+extern size_t mbs_width(const char *s);
+
+extern char *mbs_safe_encode(const char *s, size_t *width);
+extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf, const char *safechars);
+extern size_t mbs_safe_encode_size(size_t bytes);
+
+extern char *mbs_invalid_encode(const char *s, size_t *width);
+extern char *mbs_invalid_encode_to_buffer(const char *s, size_t *width, char *buf);
+
+#endif /* UTIL_LINUX_MBSALIGN_H */
diff --git a/src/utils/include/mbsedit.h b/src/utils/include/mbsedit.h
new file mode 100644
index 0000000..8d1c6c2
--- /dev/null
+++ b/src/utils/include/mbsedit.h
@@ -0,0 +1,32 @@
+#ifndef UTIL_LINUX_MBSEDIT_H
+# define UTIL_LINUX_MBSEDIT_H
+
+#include "mbsalign.h"
+#include "widechar.h"
+
+struct mbs_editor {
+ char *buf; /* buffer */
+ size_t max_bytes; /* size of the buffer */
+ size_t max_cells; /* maximal allowed number of cells */
+ size_t cur_cells; /* number of cells to print the buffer */
+ size_t cur_bytes; /* number of chars in bytes */
+ size_t cursor; /* cursor position in bytes */
+ size_t cursor_cells; /* cursor position in cells */
+};
+
+enum {
+ MBS_EDIT_LEFT,
+ MBS_EDIT_RIGHT,
+ MBS_EDIT_END,
+ MBS_EDIT_HOME
+};
+
+struct mbs_editor *mbs_new_edit(char *buf, size_t bufsz, size_t ncells);
+char *mbs_free_edit(struct mbs_editor *edit);
+
+int mbs_edit_goto(struct mbs_editor *edit, int where);
+int mbs_edit_delete(struct mbs_editor *edit);
+int mbs_edit_backspace(struct mbs_editor *edit);
+int mbs_edit_insert(struct mbs_editor *edit, wint_t c);
+
+#endif /* UTIL_LINUX_MBSEDIT_H */
diff --git a/src/utils/include/md5.h b/src/utils/include/md5.h
new file mode 100644
index 0000000..02e627b
--- /dev/null
+++ b/src/utils/include/md5.h
@@ -0,0 +1,24 @@
+#ifndef UTIL_LINUX_MD5_H
+#define UTIL_LINUX_MD5_H
+
+#include <stdint.h>
+
+#define UL_MD5LENGTH 16
+
+struct UL_MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+};
+
+void ul_MD5Init(struct UL_MD5Context *ctx);
+void ul_MD5Update(struct UL_MD5Context *ctx, unsigned char const *buf, unsigned len);
+void ul_MD5Final(unsigned char digest[UL_MD5LENGTH], struct UL_MD5Context *ctx);
+void ul_MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct UL_MD5Context UL_MD5_CTX;
+
+#endif /* !UTIL_LINUX_MD5_H */
diff --git a/src/utils/include/minix.h b/src/utils/include/minix.h
new file mode 100644
index 0000000..f28991c
--- /dev/null
+++ b/src/utils/include/minix.h
@@ -0,0 +1,85 @@
+#ifndef UTIL_LINUX_MINIX_H
+#define UTIL_LINUX_MINIX_H
+
+#include <stdint.h>
+
+struct minix_inode {
+ uint16_t i_mode;
+ uint16_t i_uid;
+ uint32_t i_size;
+ uint32_t i_time;
+ uint8_t i_gid;
+ uint8_t i_nlinks;
+ uint16_t i_zone[9];
+};
+
+struct minix2_inode {
+ uint16_t i_mode;
+ uint16_t i_nlinks;
+ uint16_t i_uid;
+ uint16_t i_gid;
+ uint32_t i_size;
+ uint32_t i_atime;
+ uint32_t i_mtime;
+ uint32_t i_ctime;
+ uint32_t i_zone[10];
+};
+
+struct minix_super_block {
+ uint16_t s_ninodes;
+ uint16_t s_nzones;
+ uint16_t s_imap_blocks;
+ uint16_t s_zmap_blocks;
+ uint16_t s_firstdatazone;
+ uint16_t s_log_zone_size;
+ uint32_t s_max_size;
+ uint16_t s_magic;
+ uint16_t s_state;
+ uint32_t s_zones;
+};
+
+/* V3 minix super-block data on disk */
+struct minix3_super_block {
+ uint32_t s_ninodes;
+ uint16_t s_pad0;
+ uint16_t s_imap_blocks;
+ uint16_t s_zmap_blocks;
+ uint16_t s_firstdatazone;
+ uint16_t s_log_zone_size;
+ uint16_t s_pad1;
+ uint32_t s_max_size;
+ uint32_t s_zones;
+ uint16_t s_magic;
+ uint16_t s_pad2;
+ uint16_t s_blocksize;
+ uint8_t s_disk_version;
+};
+
+/*
+ * Minix subpartitions are always within primary dos partition.
+ */
+#define MINIX_MAXPARTITIONS 4
+
+#define MINIX_BLOCK_SIZE_BITS 10
+#define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SIZE_BITS)
+
+#define MINIX_NAME_MAX 255 /* # chars in a file name */
+#define MINIX_MAX_INODES 65535
+
+#define MINIX_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+/* minix_super_block.s_state */
+#define MINIX_VALID_FS 0x0001 /* Clean fs. */
+#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+
+
+#define MINIX_SUPER_MAGIC 0x137F /* minix V1 fs, 14 char names */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix V1 fs, 30 char names */
+
+#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs, 14 char names */
+#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+
+#define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs (60 char names) */
+
+#endif /* UTIL_LINUX_MINIX_H */
diff --git a/src/utils/include/monotonic.h b/src/utils/include/monotonic.h
new file mode 100644
index 0000000..380e59c
--- /dev/null
+++ b/src/utils/include/monotonic.h
@@ -0,0 +1,22 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ */
+#ifndef UTIL_LINUX_MONOTONIC_H
+#define UTIL_LINUX_MONOTONIC_H
+
+# ifdef CLOCK_MONOTONIC_RAW
+# define UL_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
+# else
+# define UL_CLOCK_MONOTONIC CLOCK_MONOTONIC
+# endif
+
+#include <sys/time.h>
+
+extern int get_boot_time(struct timeval *boot_time);
+
+extern time_t get_suspended_time(void);
+
+extern int gettime_monotonic(struct timeval *tv);
+
+#endif /* UTIL_LINUX_MONOTONIC_H */
diff --git a/src/utils/include/namespace.h b/src/utils/include/namespace.h
new file mode 100644
index 0000000..2d0a56e
--- /dev/null
+++ b/src/utils/include/namespace.h
@@ -0,0 +1,56 @@
+
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Compat code so unshare and setns can be used with older libcs
+ */
+#ifndef UTIL_LINUX_NAMESPACE_H
+# define UTIL_LINUX_NAMESPACE_H
+
+# include <sched.h>
+
+# ifndef CLONE_NEWNS
+# define CLONE_NEWNS 0x00020000
+# endif
+# ifndef CLONE_NEWCGROUP
+# define CLONE_NEWCGROUP 0x02000000
+# endif
+# ifndef CLONE_NEWUTS
+# define CLONE_NEWUTS 0x04000000
+# endif
+# ifndef CLONE_NEWIPC
+# define CLONE_NEWIPC 0x08000000
+# endif
+# ifndef CLONE_NEWNET
+# define CLONE_NEWNET 0x40000000
+# endif
+# ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+# endif
+# ifndef CLONE_NEWPID
+# define CLONE_NEWPID 0x20000000
+# endif
+# ifndef CLONE_NEWTIME
+# define CLONE_NEWTIME 0x00000080
+# endif
+
+# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS)
+# include <sys/syscall.h>
+# endif
+
+# if !defined(HAVE_UNSHARE) && defined(SYS_unshare)
+static inline int unshare(int flags)
+{
+ return syscall(SYS_unshare, flags);
+}
+# endif
+
+# if !defined(HAVE_SETNS) && defined(SYS_setns)
+static inline int setns(int fd, int nstype)
+{
+ return syscall(SYS_setns, fd, nstype);
+}
+# endif
+
+#endif /* UTIL_LINUX_NAMESPACE_H */
diff --git a/src/utils/include/nls.h b/src/utils/include/nls.h
new file mode 100644
index 0000000..5566908
--- /dev/null
+++ b/src/utils/include/nls.h
@@ -0,0 +1,153 @@
+#ifndef UTIL_LINUX_NLS_H
+#define UTIL_LINUX_NLS_H
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#else
+# undef setlocale
+# define setlocale(Category, Locale) /* empty */
+struct lconv
+{
+ char *decimal_point;
+};
+# undef localeconv
+# define localeconv() NULL
+#endif
+
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+/*
+ * For NLS support in the public shared libraries we have to specify text
+ * domain name to be independent on the main program. For this purpose define
+ * UL_TEXTDOMAIN_EXPLICIT before you include nls.h to your shared library code.
+ */
+# ifdef UL_TEXTDOMAIN_EXPLICIT
+# define _(Text) dgettext (UL_TEXTDOMAIN_EXPLICIT, Text)
+# else
+# define _(Text) gettext (Text)
+# endif
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+# define P_(Singular, Plural, n) ngettext (Singular, Plural, n)
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) (Text)
+# define N_(Text) (Text)
+# define P_(Singular, Plural, n) ((n) == 1 ? (Singular) : (Plural))
+#endif /* ENABLE_NLS */
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#else
+
+typedef int nl_item;
+extern char *langinfo_fallback(nl_item item);
+
+# define nl_langinfo langinfo_fallback
+
+enum {
+ CODESET = 1,
+ RADIXCHAR,
+ THOUSEP,
+ D_T_FMT,
+ D_FMT,
+ T_FMT,
+ T_FMT_AMPM,
+ AM_STR,
+ PM_STR,
+
+ DAY_1,
+ DAY_2,
+ DAY_3,
+ DAY_4,
+ DAY_5,
+ DAY_6,
+ DAY_7,
+
+ ABDAY_1,
+ ABDAY_2,
+ ABDAY_3,
+ ABDAY_4,
+ ABDAY_5,
+ ABDAY_6,
+ ABDAY_7,
+
+ MON_1,
+ MON_2,
+ MON_3,
+ MON_4,
+ MON_5,
+ MON_6,
+ MON_7,
+ MON_8,
+ MON_9,
+ MON_10,
+ MON_11,
+ MON_12,
+
+ ABMON_1,
+ ABMON_2,
+ ABMON_3,
+ ABMON_4,
+ ABMON_5,
+ ABMON_6,
+ ABMON_7,
+ ABMON_8,
+ ABMON_9,
+ ABMON_10,
+ ABMON_11,
+ ABMON_12,
+
+ ERA_D_FMT,
+ ERA_D_T_FMT,
+ ERA_T_FMT,
+ ALT_DIGITS,
+ CRNCYSTR,
+ YESEXPR,
+ NOEXPR
+};
+
+#endif /* !HAVE_LANGINFO_H */
+
+#ifndef HAVE_LANGINFO_ALTMON
+# define ALTMON_1 MON_1
+# define ALTMON_2 MON_2
+# define ALTMON_3 MON_3
+# define ALTMON_4 MON_4
+# define ALTMON_5 MON_5
+# define ALTMON_6 MON_6
+# define ALTMON_7 MON_7
+# define ALTMON_8 MON_8
+# define ALTMON_9 MON_9
+# define ALTMON_10 MON_10
+# define ALTMON_11 MON_11
+# define ALTMON_12 MON_12
+#endif /* !HAVE_LANGINFO_ALTMON */
+
+#ifndef HAVE_LANGINFO_NL_ABALTMON
+# define _NL_ABALTMON_1 ABMON_1
+# define _NL_ABALTMON_2 ABMON_2
+# define _NL_ABALTMON_3 ABMON_3
+# define _NL_ABALTMON_4 ABMON_4
+# define _NL_ABALTMON_5 ABMON_5
+# define _NL_ABALTMON_6 ABMON_6
+# define _NL_ABALTMON_7 ABMON_7
+# define _NL_ABALTMON_8 ABMON_8
+# define _NL_ABALTMON_9 ABMON_9
+# define _NL_ABALTMON_10 ABMON_10
+# define _NL_ABALTMON_11 ABMON_11
+# define _NL_ABALTMON_12 ABMON_12
+#endif /* !HAVE_LANGINFO_NL_ABALTMON */
+
+#endif /* UTIL_LINUX_NLS_H */
diff --git a/src/utils/include/optutils.h b/src/utils/include/optutils.h
new file mode 100644
index 0000000..0dc127b
--- /dev/null
+++ b/src/utils/include/optutils.h
@@ -0,0 +1,107 @@
+#ifndef UTIL_LINUX_OPTUTILS_H
+#define UTIL_LINUX_OPTUTILS_H
+
+#include <assert.h>
+
+#include "c.h"
+#include "nls.h"
+#include "cctype.h"
+
+static inline const char *option_to_longopt(int c, const struct option *opts)
+{
+ const struct option *o;
+
+ assert(!(opts == NULL));
+ for (o = opts; o->name; o++)
+ if (o->val == c)
+ return o->name;
+ return NULL;
+}
+
+#ifndef OPTUTILS_EXIT_CODE
+# define OPTUTILS_EXIT_CODE EXIT_FAILURE
+#endif
+
+/*
+ * Check collisions between options.
+ *
+ * The conflicts between options are described in ul_excl_t array. The
+ * array contains groups of mutually exclusive options. For example
+ *
+ * static const ul_excl_t excl[] = {
+ * { 'Z','b','c' }, // first group
+ * { 'b','x' }, // second group
+ * { 0 }
+ * };
+ *
+ * int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+ *
+ * while ((c = getopt_long(argc, argv, "Zbcx", longopts, NULL)) != -1) {
+ *
+ * err_exclusive_options(c, longopts, excl, excl_st);
+ *
+ * switch (c) {
+ * case 'Z':
+ * ....
+ * }
+ * }
+ *
+ * The array excl[] defines two groups of the mutually exclusive options. The
+ * option '-b' is in the both groups.
+ *
+ * Note that the options in the group have to be in ASCII order (ABC..abc..) and
+ * groups have to be also in ASCII order.
+ *
+ * The maximal number of the options in the group is 15 (size of the array is
+ * 16, last is zero).
+ *
+ * The current status of options is stored in excl_st array. The size of the array
+ * must be the same as number of the groups in the ul_excl_t array.
+ *
+ * If you're unsure then see sys-utils/mount.c or misc-utils/findmnt.c.
+ */
+#define UL_EXCL_STATUS_INIT { 0 }
+typedef int ul_excl_t[16];
+
+static inline void err_exclusive_options(
+ int c,
+ const struct option *opts,
+ const ul_excl_t *excl,
+ int *status)
+{
+ int e;
+
+ for (e = 0; excl[e][0] && excl[e][0] <= c; e++) {
+ const int *op = excl[e];
+
+ for (; *op && *op <= c; op++) {
+ if (*op != c)
+ continue;
+ if (status[e] == 0)
+ status[e] = c;
+ else if (status[e] != c) {
+ size_t ct = 0;
+
+ fprintf(stderr, _("%s: mutually exclusive "
+ "arguments:"),
+ program_invocation_short_name);
+
+ for (op = excl[e];
+ ct + 1 < ARRAY_SIZE(excl[0]) && *op;
+ op++, ct++) {
+ const char *n = option_to_longopt(*op, opts);
+ if (n)
+ fprintf(stderr, " --%s", n);
+ else if (c_isgraph(*op))
+ fprintf(stderr, " -%c", *op);
+ }
+ fputc('\n', stderr);
+ exit(OPTUTILS_EXIT_CODE);
+ }
+ break;
+ }
+ }
+}
+
+#endif
+
diff --git a/src/utils/include/pager.h b/src/utils/include/pager.h
new file mode 100644
index 0000000..0a7140d
--- /dev/null
+++ b/src/utils/include/pager.h
@@ -0,0 +1,9 @@
+#ifndef UTIL_LINUX_PAGER
+#define UTIL_LINUX_PAGER
+
+void pager_redirect(void);
+
+void pager_open(void);
+void pager_close(void);
+
+#endif
diff --git a/src/utils/include/partx.h b/src/utils/include/partx.h
new file mode 100644
index 0000000..618a0a4
--- /dev/null
+++ b/src/utils/include/partx.h
@@ -0,0 +1,63 @@
+#ifndef UTIL_LINUX_PARTX_H
+#define UTIL_LINUX_PARTX_H
+
+#include <sys/ioctl.h>
+#include <linux/blkpg.h>
+#include <stdint.h>
+
+#ifndef BLKPG_ADD_PARTITION
+# define BLKPG_ADD_PARTITION 1
+#endif
+
+#ifndef BLKPG_DEL_PARTITION
+# define BLKPG_DEL_PARTITION 2
+#endif
+
+#ifndef BLKPG_RESIZE_PARTITION
+# define BLKPG_RESIZE_PARTITION 3 /* since Linux 3.6 */
+#endif
+
+
+#define INIT_BLKPG_PARTITION(_partno, _start, _size) { \
+ .pno = (_partno), \
+ .start = (_start) << 9, \
+ .length = (_size) << 9, \
+ .devname[0] = 0, \
+ .volname[0] = 0 \
+}
+
+#define INIT_BLKPG_ARG(_action, _part) { \
+ .op = (_action), \
+ .flags = 0, \
+ .datalen = sizeof(*(_part)), \
+ .data = (_part) \
+}
+
+
+static inline int partx_del_partition(int fd, unsigned int partno)
+{
+ struct blkpg_partition p = INIT_BLKPG_PARTITION(partno, 0, 0);
+ struct blkpg_ioctl_arg a = INIT_BLKPG_ARG(BLKPG_DEL_PARTITION, &p);
+
+ return ioctl(fd, BLKPG, &a);
+}
+
+static inline int partx_add_partition(int fd, int partno,
+ uint64_t start, uint64_t size)
+{
+ struct blkpg_partition p = INIT_BLKPG_PARTITION(partno, start, size);
+ struct blkpg_ioctl_arg a = INIT_BLKPG_ARG(BLKPG_ADD_PARTITION, &p);
+
+ return ioctl(fd, BLKPG, &a);
+}
+
+static inline int partx_resize_partition(int fd, int partno,
+ uint64_t start, uint64_t size)
+{
+ struct blkpg_partition p = INIT_BLKPG_PARTITION(partno, start, size);
+ struct blkpg_ioctl_arg a = INIT_BLKPG_ARG(BLKPG_RESIZE_PARTITION, &p);
+
+ return ioctl(fd, BLKPG, &a);
+}
+
+#endif /* UTIL_LINUX_PARTX_H */
diff --git a/src/utils/include/path.h b/src/utils/include/path.h
new file mode 100644
index 0000000..2a4f80e
--- /dev/null
+++ b/src/utils/include/path.h
@@ -0,0 +1,135 @@
+#ifndef UTIL_LINUX_PATH_H
+#define UTIL_LINUX_PATH_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "c.h"
+
+struct path_cxt {
+ int dir_fd;
+ char *dir_path;
+
+ int refcount;
+
+ char *prefix;
+ char path_buffer[PATH_MAX];
+
+ void *dialect;
+ void (*free_dialect)(struct path_cxt *);
+ int (*redirect_on_enoent)(struct path_cxt *, const char *, int *);
+};
+
+struct path_cxt *ul_new_path(const char *dir, ...);
+void ul_unref_path(struct path_cxt *pc);
+void ul_ref_path(struct path_cxt *pc);
+
+void ul_path_init_debug(void);
+
+int ul_path_set_prefix(struct path_cxt *pc, const char *prefix);
+const char *ul_path_get_prefix(struct path_cxt *pc);
+
+int ul_path_set_dir(struct path_cxt *pc, const char *dir);
+const char *ul_path_get_dir(struct path_cxt *pc);
+
+int ul_path_set_dialect(struct path_cxt *pc, void *data, void free_data(struct path_cxt *));
+void *ul_path_get_dialect(struct path_cxt *pc);
+
+int ul_path_set_enoent_redirect(struct path_cxt *pc, int (*func)(struct path_cxt *, const char *, int *));
+int ul_path_get_dirfd(struct path_cxt *pc);
+void ul_path_close_dirfd(struct path_cxt *pc);
+int ul_path_isopen_dirfd(struct path_cxt *pc);
+int ul_path_is_accessible(struct path_cxt *pc);
+
+char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+
+int ul_path_stat(struct path_cxt *pc, struct stat *sb, const char *path);
+int ul_path_access(struct path_cxt *pc, int mode, const char *path);
+int ul_path_accessf(struct path_cxt *pc, int mode, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_open(struct path_cxt *pc, int flags, const char *path);
+int ul_path_openf(struct path_cxt *pc, int flags, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+int ul_path_vopenf(struct path_cxt *pc, int flags, const char *path, va_list ap);
+
+FILE *ul_path_fopen(struct path_cxt *pc, const char *mode, const char *path);
+FILE *ul_path_fopenf(struct path_cxt *pc, const char *mode, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+FILE *ul_path_vfopenf(struct path_cxt *pc, const char *mode, const char *path, va_list ap);
+
+DIR *ul_path_opendir(struct path_cxt *pc, const char *path);
+DIR *ul_path_vopendirf(struct path_cxt *pc, const char *path, va_list ap);
+DIR *ul_path_opendirf(struct path_cxt *pc, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path);
+ssize_t ul_path_readlinkf(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+
+int ul_path_read(struct path_cxt *pc, char *buf, size_t len, const char *path);
+int ul_path_vreadf(struct path_cxt *pc, char *buf, size_t len, const char *path, va_list ap);
+int ul_path_readf(struct path_cxt *pc, char *buf, size_t len, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+
+int ul_path_read_string(struct path_cxt *pc, char **str, const char *path);
+int ul_path_readf_string(struct path_cxt *pc, char **str, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_read_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path);
+int ul_path_readf_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+
+int ul_path_scanf(struct path_cxt *pc, const char *path, const char *fmt, ...);
+int ul_path_scanff(struct path_cxt *pc, const char *path, va_list ap, const char *fmt, ...)
+ __attribute__ ((__format__ (__scanf__, 4, 5)));
+
+int ul_path_read_majmin(struct path_cxt *pc, dev_t *res, const char *path);
+int ul_path_readf_majmin(struct path_cxt *pc, dev_t *res, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_read_u32(struct path_cxt *pc, uint32_t *res, const char *path);
+int ul_path_readf_u32(struct path_cxt *pc, uint32_t *res, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_read_s32(struct path_cxt *pc, int32_t *res, const char *path);
+int ul_path_readf_s32(struct path_cxt *pc, int32_t *res, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_read_u64(struct path_cxt *pc, uint64_t *res, const char *path);
+int ul_path_readf_u64(struct path_cxt *pc, uint64_t *res, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_read_s64(struct path_cxt *pc, int64_t *res, const char *path);
+int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_write_string(struct path_cxt *pc, const char *str, const char *path);
+int ul_path_writef_string(struct path_cxt *pc, const char *str, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_write_s64(struct path_cxt *pc, int64_t num, const char *path);
+int ul_path_write_u64(struct path_cxt *pc, uint64_t num, const char *path);
+int ul_path_writef_u64(struct path_cxt *pc, uint64_t num, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+int ul_path_count_dirents(struct path_cxt *pc, const char *path);
+int ul_path_countf_dirents(struct path_cxt *pc, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+FILE *ul_prefix_fopen(const char *prefix, const char *path, const char *mode);
+
+
+#ifdef HAVE_CPU_SET_T
+# include "cpuset.h"
+int ul_path_readf_cpuset(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+
+int ul_path_readf_cpulist(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...)
+ __attribute__ ((__format__ (__printf__, 4, 5)));
+#endif /* HAVE_CPU_SET_T */
+#endif /* UTIL_LINUX_PATH_H */
diff --git a/src/utils/include/pathnames.h b/src/utils/include/pathnames.h
new file mode 100644
index 0000000..8f1bb56
--- /dev/null
+++ b/src/utils/include/pathnames.h
@@ -0,0 +1,210 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ */
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+
+#ifndef __STDC__
+# error "we need an ANSI compiler"
+#endif
+
+/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */
+#define PATH_DELETED_SUFFIX " (deleted)"
+
+/* DEFPATHs from <paths.h> don't include /usr/local */
+#undef _PATH_DEFPATH
+
+#ifdef USE_USRDIR_PATHS_ONLY
+# define _PATH_DEFPATH "/usr/local/bin:/usr/bin"
+#else
+# define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin"
+#endif
+
+#undef _PATH_DEFPATH_ROOT
+
+#ifdef USE_USRDIR_PATHS_ONLY
+# define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
+#else
+# define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
+#endif
+
+#define _PATH_HUSHLOGIN ".hushlogin"
+#define _PATH_HUSHLOGINS "/etc/hushlogins"
+
+#define _PATH_NOLOGIN_TXT "/etc/nologin.txt"
+
+#ifndef _PATH_MAILDIR
+# define _PATH_MAILDIR "/var/spool/mail"
+#endif
+#define _PATH_MOTDFILE "/usr/share/misc/motd:/run/motd:/etc/motd"
+#ifndef _PATH_NOLOGIN
+# define _PATH_NOLOGIN "/etc/nologin"
+#endif
+#define _PATH_VAR_NOLOGIN "/var/run/nologin"
+
+#ifndef _PATH_LOGIN
+# define _PATH_LOGIN "/bin/login"
+#endif
+#define _PATH_SHUTDOWN "/sbin/shutdown"
+#define _PATH_POWEROFF "/sbin/poweroff"
+
+#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d"
+#define _PATH_TERMCOLORS_DIR "/etc/" _PATH_TERMCOLORS_DIRNAME
+
+/* login paths */
+#define _PATH_PASSWD "/etc/passwd"
+#define _PATH_GSHADOW "/etc/gshadow"
+#define _PATH_GROUP "/etc/group"
+#define _PATH_SHADOW_PASSWD "/etc/shadow"
+#define _PATH_SHELLS "/etc/shells"
+
+#ifndef _PATH_TMP
+# define _PATH_TMP "/tmp/"
+#endif
+
+#ifndef _PATH_BTMP
+# define _PATH_BTMP "/var/log/btmp"
+#endif
+
+#define _PATH_ISSUE_FILENAME "issue"
+#define _PATH_ISSUE_DIRNAME _PATH_ISSUE_FILENAME ".d"
+
+#define _PATH_ISSUE "/etc/" _PATH_ISSUE_FILENAME
+#define _PATH_ISSUEDIR "/etc/" _PATH_ISSUE_DIRNAME
+
+#define _PATH_OS_RELEASE_ETC "/etc/os-release"
+#define _PATH_OS_RELEASE_USR "/usr/lib/os-release"
+#define _PATH_NUMLOCK_ON _PATH_RUNSTATEDIR "/numlock-on"
+#define _PATH_LOGINDEFS "/etc/login.defs"
+
+/* misc paths */
+#define _PATH_WORDS "/usr/share/dict/words"
+#define _PATH_WORDS_ALT "/usr/share/dict/web2"
+
+/* mount paths */
+#define _PATH_FILESYSTEMS "/etc/filesystems"
+#define _PATH_PROC_SWAPS "/proc/swaps"
+#define _PATH_PROC_FILESYSTEMS "/proc/filesystems"
+#define _PATH_PROC_MOUNTS "/proc/mounts"
+#define _PATH_PROC_PARTITIONS "/proc/partitions"
+#define _PATH_PROC_DEVICES "/proc/devices"
+#define _PATH_PROC_MOUNTINFO "/proc/self/mountinfo"
+#define _PATH_PROC_LOCKS "/proc/locks"
+#define _PATH_PROC_CDROMINFO "/proc/sys/dev/cdrom/info"
+
+#define _PATH_PROC_UIDMAP "/proc/self/uid_map"
+#define _PATH_PROC_GIDMAP "/proc/self/gid_map"
+#define _PATH_PROC_SETGROUPS "/proc/self/setgroups"
+
+#define _PATH_PROC_FDDIR "/proc/self/fd"
+
+#define _PATH_PROC_ATTR_CURRENT "/proc/self/attr/current"
+#define _PATH_PROC_ATTR_EXEC "/proc/self/attr/exec"
+#define _PATH_PROC_CAPLASTCAP "/proc/sys/kernel/cap_last_cap"
+
+
+#define _PATH_SYS_BLOCK "/sys/block"
+#define _PATH_SYS_DEVBLOCK "/sys/dev/block"
+#define _PATH_SYS_DEVCHAR "/sys/dev/char"
+#define _PATH_SYS_CLASS "/sys/class"
+#define _PATH_SYS_SCSI "/sys/bus/scsi"
+
+#define _PATH_SYS_SELINUX "/sys/fs/selinux"
+#define _PATH_SYS_APPARMOR "/sys/kernel/security/apparmor"
+
+#ifndef _PATH_MOUNTED
+# ifdef MOUNTED /* deprecated */
+# define _PATH_MOUNTED MOUNTED
+# else
+# define _PATH_MOUNTED "/etc/mtab"
+# endif
+#endif
+
+#ifndef _PATH_MNTTAB
+# ifdef MNTTAB /* deprecated */
+# define _PATH_MNTTAB MNTTAB
+# else
+# define _PATH_MNTTAB "/etc/fstab"
+# endif
+#endif
+
+#ifndef _PATH_DEV
+ /*
+ * The tailing '/' in _PATH_DEV is there for compatibility with libc.
+ */
+# define _PATH_DEV "/dev/"
+#endif
+
+#define _PATH_DEV_MAPPER "/dev/mapper"
+
+#define _PATH_DEV_MEM "/dev/mem"
+
+#define _PATH_DEV_LOOP "/dev/xloop"
+#define _PATH_DEV_LOOPCTL "/dev/xloop-control"
+
+/* udev paths */
+#define _PATH_DEV_BYLABEL "/dev/disk/by-label"
+#define _PATH_DEV_BYUUID "/dev/disk/by-uuid"
+#define _PATH_DEV_BYID "/dev/disk/by-id"
+#define _PATH_DEV_BYPATH "/dev/disk/by-path"
+#define _PATH_DEV_BYPARTLABEL "/dev/disk/by-partlabel"
+#define _PATH_DEV_BYPARTUUID "/dev/disk/by-partuuid"
+
+/* hwclock paths */
+#ifdef CONFIG_ADJTIME_PATH
+# define _PATH_ADJTIME CONFIG_ADJTIME_PATH
+#else
+# define _PATH_ADJTIME "/etc/adjtime"
+#endif
+
+#ifdef __ia64__
+# define _PATH_RTC_DEV "/dev/efirtc"
+#else
+# define _PATH_RTC_DEV "/dev/rtc0"
+#endif
+
+/* raw paths*/
+#define _PATH_RAWDEVDIR "/dev/raw/"
+#define _PATH_RAWDEVCTL _PATH_RAWDEVDIR "rawctl"
+/* deprecated */
+#define _PATH_RAWDEVCTL_OLD "/dev/rawctl"
+
+/* ipc paths */
+#define _PATH_PROC_SYSV_MSG "/proc/sysvipc/msg"
+#define _PATH_PROC_SYSV_SEM "/proc/sysvipc/sem"
+#define _PATH_PROC_SYSV_SHM "/proc/sysvipc/shm"
+#define _PATH_PROC_IPC_MSGMAX "/proc/sys/kernel/msgmax"
+#define _PATH_PROC_IPC_MSGMNB "/proc/sys/kernel/msgmnb"
+#define _PATH_PROC_IPC_MSGMNI "/proc/sys/kernel/msgmni"
+#define _PATH_PROC_IPC_SEM "/proc/sys/kernel/sem"
+#define _PATH_PROC_IPC_SHMALL "/proc/sys/kernel/shmall"
+#define _PATH_PROC_IPC_SHMMAX "/proc/sys/kernel/shmmax"
+#define _PATH_PROC_IPC_SHMMNI "/proc/sys/kernel/shmmni"
+
+/* irqtop paths */
+#define _PATH_PROC_INTERRUPTS "/proc/interrupts"
+#define _PATH_PROC_SOFTIRQS "/proc/softirqs"
+#define _PATH_PROC_UPTIME "/proc/uptime"
+
+/* kernel command line */
+#define _PATH_PROC_CMDLINE "/proc/cmdline"
+
+/* logger paths */
+#define _PATH_DEVLOG "/dev/log"
+
+/* ctrlaltdel paths */
+#define _PATH_PROC_CTRL_ALT_DEL "/proc/sys/kernel/ctrl-alt-del"
+
+/* lscpu paths */
+#define _PATH_PROC_CPUINFO "/proc/cpuinfo"
+
+/* rfkill paths */
+#define _PATH_DEV_RFKILL "/dev/rfkill"
+#define _PATH_SYS_RFKILL "/sys/class/rfkill"
+
+#endif /* PATHNAMES_H */
diff --git a/src/utils/include/pidfd-utils.h b/src/utils/include/pidfd-utils.h
new file mode 100644
index 0000000..4a6c3a6
--- /dev/null
+++ b/src/utils/include/pidfd-utils.h
@@ -0,0 +1,28 @@
+#ifndef UTIL_LINUX_PIDFD_UTILS
+#define UTIL_LINUX_PIDFD_UTILS
+
+#if defined(__linux__)
+# include <sys/syscall.h>
+# if defined(SYS_pidfd_send_signal) && defined(SYS_pidfd_open)
+# include <sys/types.h>
+
+# ifndef HAVE_PIDFD_SEND_SIGNAL
+static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
+ unsigned int flags)
+{
+ return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags);
+}
+# endif
+
+# ifndef HAVE_PIDFD_OPEN
+static inline int pidfd_open(pid_t pid, unsigned int flags)
+{
+ return syscall(SYS_pidfd_open, pid, flags);
+}
+# endif
+
+# define UL_HAVE_PIDFD 1
+
+# endif /* SYS_pidfd_send_signal */
+#endif /* __linux__ */
+#endif /* UTIL_LINUX_PIDFD_UTILS */
diff --git a/src/utils/include/plymouth-ctrl.h b/src/utils/include/plymouth-ctrl.h
new file mode 100644
index 0000000..b6f1299
--- /dev/null
+++ b/src/utils/include/plymouth-ctrl.h
@@ -0,0 +1,65 @@
+/*
+ * plymouth-ctrl.h Header file for communications with plymouthd
+ *
+ * Copyright (c) 2016 SUSE Linux GmbH, All rights reserved.
+ * Copyright (c) 2016 Werner Fink <werner@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+/*
+ * Taken from plymouth 0.9.0 src/ply-boot-protocol.h
+ */
+
+#ifndef UTIL_LINUX_PLYMOUTH_CTRL_H
+#define UTIL_LINUX_PLYMOUTH_CTRL_H
+
+#define PLYMOUTH_SOCKET_PATH "\0/org/freedesktop/plymouthd"
+#define ANSWER_TYP '\x2'
+#define ANSWER_ENQ '\x5'
+#define ANSWER_ACK '\x6'
+#define ANSWER_MLT '\t'
+#define ANSWER_NCK '\x15'
+
+#define MAGIC_PRG_STOP 'A'
+#define MAGIC_PRG_CONT 'a'
+#define MAGIC_UPDATE 'U'
+#define MAGIC_SYS_UPDATE 'u'
+#define MAGIC_SYS_INIT 'S'
+#define MAGIC_DEACTIVATE 'D'
+#define MAGIC_REACTIVATE 'r'
+#define MAGIC_SHOW_SPLASH '$'
+#define MAGIC_HIDE_SPLASH 'H'
+#define MAGIC_CHMOD 'C'
+#define MAGIC_CHROOT 'R'
+#define MAGIC_ACTIVE_VT 'V'
+#define MAGIC_QUESTION 'W'
+#define MAGIC_SHOW_MSG 'M'
+#define MAGIC_HIDE_MSG 'm'
+#define MAGIC_KEYSTROKE 'K'
+#define MAGIC_KEYSTROKE_RM 'L'
+#define MAGIC_PING 'P'
+#define MAGIC_QUIT 'Q'
+#define MAGIC_CACHED_PWD 'c'
+#define MAGIC_ASK_PWD '*'
+#define MAGIC_DETAILS '!'
+
+#define PLYMOUTH_TERMIOS_FLAGS_DELAY 30
+extern int plymouth_command(int cmd, ...);
+
+#endif /* UTIL_LINUX_PLYMOUTH_CTRL_H */
diff --git a/src/utils/include/procutils.h b/src/utils/include/procutils.h
new file mode 100644
index 0000000..9f8dd76
--- /dev/null
+++ b/src/utils/include/procutils.h
@@ -0,0 +1,34 @@
+#ifndef UTIL_LINUX_PROCUTILS
+#define UTIL_LINUX_PROCUTILS
+
+#include <dirent.h>
+
+struct proc_tasks {
+ DIR *dir;
+};
+
+extern struct proc_tasks *proc_open_tasks(pid_t pid);
+extern void proc_close_tasks(struct proc_tasks *tasks);
+extern int proc_next_tid(struct proc_tasks *tasks, pid_t *tid);
+
+struct proc_processes {
+ DIR *dir;
+
+ const char *fltr_name;
+ uid_t fltr_uid;
+
+ unsigned int has_fltr_name : 1,
+ has_fltr_uid : 1;
+};
+
+extern struct proc_processes *proc_open_processes(void);
+extern void proc_close_processes(struct proc_processes *ps);
+
+extern void proc_processes_filter_by_name(struct proc_processes *ps, const char *name);
+extern void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid);
+extern int proc_next_pid(struct proc_processes *ps, pid_t *pid);
+
+extern char *proc_get_command(pid_t pid);
+extern char *proc_get_command_name(pid_t pid);
+
+#endif /* UTIL_LINUX_PROCUTILS */
diff --git a/src/utils/include/pt-bsd.h b/src/utils/include/pt-bsd.h
new file mode 100644
index 0000000..9bf47a5
--- /dev/null
+++ b/src/utils/include/pt-bsd.h
@@ -0,0 +1,156 @@
+#ifndef UTIL_LINUX_PT_BSD_H
+#define UTIL_LINUX_PT_BSD_H
+
+#define BSD_MAXPARTITIONS 16
+#define BSD_FS_UNUSED 0
+
+#ifndef BSD_DISKMAGIC
+# define BSD_DISKMAGIC ((uint32_t) 0x82564557)
+#endif
+
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (__alpha__) || defined (__powerpc__) || \
+ defined (__ia64__) || defined (__hppa__)
+# define BSD_LABELSECTOR 0
+# define BSD_LABELOFFSET 64
+#else
+# define BSD_LABELSECTOR 1
+# define BSD_LABELOFFSET 0
+#endif
+
+#define BSD_BBSIZE 8192 /* size of boot area, with label */
+#define BSD_SBSIZE 8192 /* max size of fs superblock */
+
+struct bsd_disklabel {
+ uint32_t d_magic; /* the magic number */
+ int16_t d_type; /* drive type */
+ int16_t d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+ char d_packname[16]; /* pack identifier */
+
+ /* disk geometry: */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_ncylinders; /* # of data cylinders per unit */
+ uint32_t d_secpercyl; /* # of data sectors per cylinder */
+ uint32_t d_secperunit; /* # of data sectors per unit */
+
+ /*
+ * Spares (bad sector replacements) below
+ * are not counted in d_nsectors or d_secpercyl.
+ * Spare sectors are assumed to be physical sectors
+ * which occupy space at the end of each track and/or cylinder.
+ */
+ uint16_t d_sparespertrack; /* # of spare sectors per track */
+ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
+
+ /*
+ * Alternate cylinders include maintenance, replacement,
+ * configuration description areas, etc.
+ */
+ uint32_t d_acylinders; /* # of alt. cylinders per unit */
+
+ /* hardware characteristics: */
+ /*
+ * d_interleave, d_trackskew and d_cylskew describe perturbations
+ * in the media format used to compensate for a slow controller.
+ * Interleave is physical sector interleave, set up by the formatter
+ * or controller when formatting. When interleaving is in use,
+ * logically adjacent sectors are not physically contiguous,
+ * but instead are separated by some number of sectors.
+ * It is specified as the ratio of physical sectors traversed
+ * per logical sector. Thus an interleave of 1:1 implies contiguous
+ * layout, while 2:1 implies that logical sector 0 is separated
+ * by one sector from logical sector 1.
+ * d_trackskew is the offset of sector 0 on track N
+ * relative to sector 0 on track N-1 on the same cylinder.
+ * Finally, d_cylskew is the offset of sector 0 on cylinder N
+ * relative to sector 0 on cylinder N-1.
+ */
+ uint16_t d_rpm; /* rotational speed */
+ uint16_t d_interleave; /* hardware sector interleave */
+ uint16_t d_trackskew; /* sector 0 skew, per track */
+ uint16_t d_cylskew; /* sector 0 skew, per cylinder */
+ uint32_t d_headswitch; /* head switch time, usec */
+ uint32_t d_trkseek; /* track-to-track seek, usec */
+ uint32_t d_flags; /* generic flags */
+ uint32_t d_drivedata[5]; /* drive-type specific information */
+ uint32_t d_spare[5]; /* reserved for future use */
+ uint32_t d_magic2; /* the magic number (again) */
+ uint16_t d_checksum; /* xor of data incl. partitions */
+
+ /* filesystem and partition information: */
+ uint16_t d_npartitions; /* number of partitions in following */
+ uint32_t d_bbsize; /* size of boot area at sn0, bytes */
+ uint32_t d_sbsize; /* max size of fs superblock, bytes */
+
+ struct bsd_partition { /* the partition table */
+ uint32_t p_size; /* number of sectors in partition */
+ uint32_t p_offset; /* starting sector */
+ uint32_t p_fsize; /* filesystem basic fragment size */
+ uint8_t p_fstype; /* filesystem type, see below */
+ uint8_t p_frag; /* filesystem fragments per block */
+ uint16_t p_cpg; /* filesystem cylinders per group */
+ } __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+} __attribute__((packed));
+
+
+/* d_type values: */
+#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
+#define BSD_DTYPE_MSCP 2 /* MSCP */
+#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
+#define BSD_DTYPE_SCSI 4 /* SCSI */
+#define BSD_DTYPE_ESDI 5 /* ESDI interface */
+#define BSD_DTYPE_ST506 6 /* ST506 etc. */
+#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
+#define BSD_DTYPE_FLOPPY 10 /* floppy */
+
+/* d_subtype values: */
+#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
+#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
+#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
+
+/*
+ * Filesystem type and version.
+ * Used to interpret other filesystem-specific
+ * per-partition information.
+ */
+#define BSD_FS_UNUSED 0 /* unused */
+#define BSD_FS_SWAP 1 /* swap */
+#define BSD_FS_V6 2 /* Sixth Edition */
+#define BSD_FS_V7 3 /* Seventh Edition */
+#define BSD_FS_SYSV 4 /* System V */
+#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
+#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
+#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
+#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
+#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
+#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
+#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
+#define BSD_FS_ISOFS BSD_FS_ISO9660
+#define BSD_FS_BOOT 13 /* partition contains bootstrap */
+#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
+#define BSD_FS_HFS 15 /* Macintosh HFS */
+#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
+
+/* this is annoying, but it's also the way it is :-( */
+#ifdef __alpha__
+#define BSD_FS_EXT2 8 /* ext2 file system */
+#else
+#define BSD_FS_MSDOS 8 /* MS-DOS file system */
+#endif
+
+/*
+ * flags shared by various drives:
+ */
+#define BSD_D_REMOVABLE 0x01 /* removable media */
+#define BSD_D_ECC 0x02 /* supports ECC */
+#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
+#define BSD_D_RAMDISK 0x08 /* disk emulator */
+#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
+#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
+
+#endif /* UTIL_LINUX_PT_BSD_H */
diff --git a/src/utils/include/pt-gpt-partnames.h b/src/utils/include/pt-gpt-partnames.h
new file mode 100644
index 0000000..604f2c6
--- /dev/null
+++ b/src/utils/include/pt-gpt-partnames.h
@@ -0,0 +1,160 @@
+
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ *
+ * Probably the most complete list of the GUIDs are at:
+ * https://wikipedia.org/wiki/GUID_Partition_Table
+ *
+ * The macro DEF_GUID() has to be defined in your code according to array where
+ * you want to include this file.
+ */
+
+/* Generic OS */
+DEF_GUID("C12A7328-F81F-11D2-BA4B-00A0C93EC93B", N_("EFI System")),
+
+DEF_GUID("024DEE41-33E7-11D3-9D69-0008C781F39F", N_("MBR partition scheme")),
+DEF_GUID("D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", N_("Intel Fast Flash")),
+
+/* Hah!IdontneedEFI */
+DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot")),
+
+/* NIH syndrome */
+DEF_GUID("F4019732-066E-4E12-8273-346C5641494F", N_("Sony boot partition")),
+DEF_GUID("BFBFAFE7-A34F-448A-9A5B-6213EB736C22", N_("Lenovo boot partition")),
+
+/* PowerPC reference platform boot partition */
+DEF_GUID("9E1A2D38-C612-4316-AA26-8B49521E5A8B", N_("PowerPC PReP boot")),
+
+/* Open Network Install Environment */
+DEF_GUID("7412F7D5-A156-4B13-81DC-867174929325", N_("ONIE boot")),
+DEF_GUID("D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149", N_("ONIE config")),
+
+/* Windows */
+DEF_GUID("E3C9E316-0B5C-4DB8-817D-F92DF00215AE", N_("Microsoft reserved")),
+DEF_GUID("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", N_("Microsoft basic data")),
+DEF_GUID("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", N_("Microsoft LDM metadata")),
+DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")),
+DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")),
+DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")),
+DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")),
+
+/* HP-UX */
+DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")),
+DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service")),
+
+/* Linux (https://systemd.io/DISCOVERABLE_PARTITIONS/) */
+DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")),
+DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")),
+DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")),
+DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")),
+DEF_GUID("69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", N_("Linux root (ARM)")),
+DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")),
+DEF_GUID("B921B045-1DF0-41C3-AF44-4C6F280D3FAE", N_("Linux root (ARM-64)")),
+DEF_GUID("993D8D3D-F80E-4225-855A-9DAF8ED7EA97", N_("Linux root (IA-64)")),
+DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")),
+DEF_GUID("933AC7E1-2EB4-4F13-B844-0E14E2AEF915", N_("Linux home")),
+DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")),
+DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")),
+DEF_GUID("4D21B016-B534-45C2-A9FB-5C16E091FD2D", N_("Linux variable data")),
+DEF_GUID("7EC6F557-3BC5-4ACA-B293-16EF5DF639D1", N_("Linux temporary data")),
+DEF_GUID("D13C5D3B-B5D1-422A-B29F-9454FDC89D76", N_("Linux root verity (x86)")),
+DEF_GUID("7386CDF2-203C-47A9-A498-F2ECCE45A2D6", N_("Linux root verity (ARM)")),
+DEF_GUID("2C7357ED-EBD2-46D9-AEC1-23D437EC2BF5", N_("Linux root verity (x86-64)")),
+DEF_GUID("DF3300CE-D69F-4C92-978C-9BFB0F38D820", N_("Linux root verity (ARM-64)")),
+DEF_GUID("86ED10D5-B607-45BB-8957-D350F23D0571", N_("Linux root verity (IA-64)")),
+/* ... too crazy, ignore for now:
+DEF_GUID("7FFEC5C9-2D00-49B7-8941-3EA10A5586B7", N_("Linux plain dm-crypt")),
+DEF_GUID("CA7D7CCB-63ED-4C53-861C-1742536059CC", N_("Linux LUKS")),
+*/
+/* Linux https://systemd.io/BOOT_LOADER_SPECIFICATION/ */
+DEF_GUID("BC13C2FF-59E6-4262-A352-B275FD6F7172", N_("Linux extended boot")),
+
+/* Linux https://systemd.io/HOME_DIRECTORY/ */
+DEF_GUID("773f91ef-66d4-49b5-bd83-d683bf40ad16", N_("Linux user's home")),
+
+/* FreeBSD */
+DEF_GUID("516E7CB4-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD data")),
+DEF_GUID("83BD6B9D-7F41-11DC-BE0B-001560B84F0F", N_("FreeBSD boot")),
+DEF_GUID("516E7CB5-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD swap")),
+DEF_GUID("516E7CB6-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD UFS")),
+DEF_GUID("516E7CBA-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD ZFS")),
+DEF_GUID("516E7CB8-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD Vinum")),
+
+/* Apple OSX */
+DEF_GUID("48465300-0000-11AA-AA11-00306543ECAC", N_("Apple HFS/HFS+")),
+DEF_GUID("7C3457EF-0000-11AA-AA11-00306543ECAC", N_("Apple APFS")),
+DEF_GUID("55465300-0000-11AA-AA11-00306543ECAC", N_("Apple UFS")),
+DEF_GUID("52414944-0000-11AA-AA11-00306543ECAC", N_("Apple RAID")),
+DEF_GUID("52414944-5F4F-11AA-AA11-00306543ECAC", N_("Apple RAID offline")),
+DEF_GUID("426F6F74-0000-11AA-AA11-00306543ECAC", N_("Apple boot")),
+DEF_GUID("4C616265-6C00-11AA-AA11-00306543ECAC", N_("Apple label")),
+DEF_GUID("5265636F-7665-11AA-AA11-00306543ECAC", N_("Apple TV recovery")),
+DEF_GUID("53746F72-6167-11AA-AA11-00306543ECAC", N_("Apple Core storage")),
+
+/* Solaris */
+DEF_GUID("6A82CB45-1DD2-11B2-99A6-080020736631", N_("Solaris boot")),
+DEF_GUID("6A85CF4D-1DD2-11B2-99A6-080020736631", N_("Solaris root")),
+/* same as Apple ZFS */
+DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("Solaris /usr & Apple ZFS")),
+DEF_GUID("6A87C46F-1DD2-11B2-99A6-080020736631", N_("Solaris swap")),
+DEF_GUID("6A8B642B-1DD2-11B2-99A6-080020736631", N_("Solaris backup")),
+DEF_GUID("6A8EF2E9-1DD2-11B2-99A6-080020736631", N_("Solaris /var")),
+DEF_GUID("6A90BA39-1DD2-11B2-99A6-080020736631", N_("Solaris /home")),
+DEF_GUID("6A9283A5-1DD2-11B2-99A6-080020736631", N_("Solaris alternate sector")),
+DEF_GUID("6A945A3B-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 1")),
+DEF_GUID("6A9630D1-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 2")),
+DEF_GUID("6A980767-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 3")),
+DEF_GUID("6A96237F-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 4")),
+DEF_GUID("6A8D2AC7-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 5")),
+
+/* NetBSD */
+DEF_GUID("49F48D32-B10E-11DC-B99B-0019D1879648", N_("NetBSD swap")),
+DEF_GUID("49F48D5A-B10E-11DC-B99B-0019D1879648", N_("NetBSD FFS")),
+DEF_GUID("49F48D82-B10E-11DC-B99B-0019D1879648", N_("NetBSD LFS")),
+DEF_GUID("2DB519C4-B10E-11DC-B99B-0019D1879648", N_("NetBSD concatenated")),
+DEF_GUID("2DB519EC-B10E-11DC-B99B-0019D1879648", N_("NetBSD encrypted")),
+DEF_GUID("49F48DAA-B10E-11DC-B99B-0019D1879648", N_("NetBSD RAID")),
+
+/* ChromeOS */
+DEF_GUID("FE3A2A5D-4F32-41A7-B725-ACCC3285A309", N_("ChromeOS kernel")),
+DEF_GUID("3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", N_("ChromeOS root fs")),
+DEF_GUID("2E0A753D-9E48-43B0-8337-B15192CB1B5E", N_("ChromeOS reserved")),
+
+/* MidnightBSD */
+DEF_GUID("85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD data")),
+DEF_GUID("85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD boot")),
+DEF_GUID("85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD swap")),
+DEF_GUID("0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")),
+DEF_GUID("85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD ZFS")),
+DEF_GUID("85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD Vinum")),
+
+/* Ceph */
+DEF_GUID("45B0969E-9B03-4F30-B4C6-B4B80CEFF106", N_("Ceph Journal")),
+DEF_GUID("45B0969E-9B03-4F30-B4C6-5EC00CEFF106", N_("Ceph Encrypted Journal")),
+DEF_GUID("4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D", N_("Ceph OSD")),
+DEF_GUID("4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D", N_("Ceph crypt OSD")),
+DEF_GUID("89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE", N_("Ceph disk in creation")),
+DEF_GUID("89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE", N_("Ceph crypt disk in creation")),
+
+/* VMware */
+DEF_GUID("AA31E02A-400F-11DB-9590-000C2911D1B8", N_("VMware VMFS")),
+DEF_GUID("9D275380-40AD-11DB-BF97-000C2911D1B8", N_("VMware Diagnostic")),
+DEF_GUID("381CFCCC-7288-11E0-92EE-000C2911D0B2", N_("VMware Virtual SAN")),
+DEF_GUID("77719A0C-A4A0-11E3-A47E-000C29745A24", N_("VMware Virsto")),
+DEF_GUID("9198EFFC-31C0-11DB-8F78-000C2911D1B8", N_("VMware Reserved")),
+
+/* OpenBSD */
+DEF_GUID("824CC7A0-36A8-11E3-890A-952519AD3F61", N_("OpenBSD data")),
+
+/* QNX */
+DEF_GUID("CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1", N_("QNX6 file system")),
+
+/* Plan 9 */
+DEF_GUID("C91818F9-8025-47AF-89D2-F030D7000C2C", N_("Plan 9 partition")),
+
+/* HiFive Unleased bootloaders */
+DEF_GUID("5B193300-FC78-40CD-8002-E86C45580B47", N_("HiFive Unleashed FSBL")),
+DEF_GUID("2E54B353-1271-4842-806F-E436D6AF6985", N_("HiFive Unleashed BBL")),
diff --git a/src/utils/include/pt-mbr-partnames.h b/src/utils/include/pt-mbr-partnames.h
new file mode 100644
index 0000000..19a3450
--- /dev/null
+++ b/src/utils/include/pt-mbr-partnames.h
@@ -0,0 +1,112 @@
+ {0x00, N_("Empty")},
+ {0x01, N_("FAT12")},
+ {0x02, N_("XENIX root")},
+ {0x03, N_("XENIX usr")},
+ {0x04, N_("FAT16 <32M")},
+ {0x05, N_("Extended")}, /* DOS 3.3+ extended partition */
+ {0x06, N_("FAT16")}, /* DOS 16-bit >=32M */
+ {0x07, N_("HPFS/NTFS/exFAT")}, /* OS/2 IFS, eg, HPFS or NTFS or QNX or exFAT */
+ {0x08, N_("AIX")}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ {0x09, N_("AIX bootable")}, /* AIX data or Coherent */
+ {0x0a, N_("OS/2 Boot Manager")},/* OS/2 Boot Manager */
+ {0x0b, N_("W95 FAT32")},
+ {0x0c, N_("W95 FAT32 (LBA)")},/* LBA really is `Extended Int 13h' */
+ {0x0e, N_("W95 FAT16 (LBA)")},
+ {0x0f, N_("W95 Ext'd (LBA)")},
+ {0x10, N_("OPUS")},
+ {0x11, N_("Hidden FAT12")},
+ {0x12, N_("Compaq diagnostics")},
+ {0x14, N_("Hidden FAT16 <32M")},
+ {0x16, N_("Hidden FAT16")},
+ {0x17, N_("Hidden HPFS/NTFS")},
+ {0x18, N_("AST SmartSleep")},
+ {0x1b, N_("Hidden W95 FAT32")},
+ {0x1c, N_("Hidden W95 FAT32 (LBA)")},
+ {0x1e, N_("Hidden W95 FAT16 (LBA)")},
+ {0x24, N_("NEC DOS")},
+ {0x27, N_("Hidden NTFS WinRE")},
+ {0x39, N_("Plan 9")},
+ {0x3c, N_("PartitionMagic recovery")},
+ {0x40, N_("Venix 80286")},
+ {0x41, N_("PPC PReP Boot")},
+ {0x42, N_("SFS")},
+ {0x4d, N_("QNX4.x")},
+ {0x4e, N_("QNX4.x 2nd part")},
+ {0x4f, N_("QNX4.x 3rd part")},
+ {0x50, N_("OnTrack DM")},
+ {0x51, N_("OnTrack DM6 Aux1")}, /* (or Novell) */
+ {0x52, N_("CP/M")}, /* CP/M or Microport SysV/AT */
+ {0x53, N_("OnTrack DM6 Aux3")},
+ {0x54, N_("OnTrackDM6")},
+ {0x55, N_("EZ-Drive")},
+ {0x56, N_("Golden Bow")},
+ {0x5c, N_("Priam Edisk")},
+ {0x61, N_("SpeedStor")},
+ {0x63, N_("GNU HURD or SysV")}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ {0x64, N_("Novell Netware 286")},
+ {0x65, N_("Novell Netware 386")},
+ {0x70, N_("DiskSecure Multi-Boot")},
+ {0x75, N_("PC/IX")},
+ {0x80, N_("Old Minix")}, /* Minix 1.4a and earlier */
+ {0x81, N_("Minix / old Linux")},/* Minix 1.4b and later */
+ {0x82, N_("Linux swap / Solaris")},
+ {0x83, N_("Linux")},
+ {0x84, N_("OS/2 hidden or Intel hibernation")},/* OS/2 hidden C: drive,
+ hibernation type Microsoft APM
+ or hibernation Intel Rapid Start */
+ {0x85, N_("Linux extended")},
+ {0x86, N_("NTFS volume set")},
+ {0x87, N_("NTFS volume set")},
+ {0x88, N_("Linux plaintext")},
+ {0x8e, N_("Linux LVM")},
+ {0x93, N_("Amoeba")},
+ {0x94, N_("Amoeba BBT")}, /* (bad block table) */
+ {0x9f, N_("BSD/OS")}, /* BSDI */
+ {0xa0, N_("IBM Thinkpad hibernation")},
+ {0xa5, N_("FreeBSD")}, /* various BSD flavours */
+ {0xa6, N_("OpenBSD")},
+ {0xa7, N_("NeXTSTEP")},
+ {0xa8, N_("Darwin UFS")},
+ {0xa9, N_("NetBSD")},
+ {0xab, N_("Darwin boot")},
+ {0xaf, N_("HFS / HFS+")},
+ {0xb7, N_("BSDI fs")},
+ {0xb8, N_("BSDI swap")},
+ {0xbb, N_("Boot Wizard hidden")},
+ {0xbc, N_("Acronis FAT32 LBA")},/* hidden (+0xb0) Acronis Secure Zone (backup software) */
+ {0xbe, N_("Solaris boot")},
+ {0xbf, N_("Solaris")},
+ {0xc1, N_("DRDOS/sec (FAT-12)")},
+ {0xc4, N_("DRDOS/sec (FAT-16 < 32M)")},
+ {0xc6, N_("DRDOS/sec (FAT-16)")},
+ {0xc7, N_("Syrinx")},
+ {0xda, N_("Non-FS data")},
+ {0xdb, N_("CP/M / CTOS / ...")},/* CP/M or Concurrent CP/M or
+ Concurrent DOS or CTOS */
+ {0xde, N_("Dell Utility")}, /* Dell PowerEdge Server utilities */
+ {0xdf, N_("BootIt")}, /* BootIt EMBRM */
+ {0xe1, N_("DOS access")}, /* DOS access or SpeedStor 12-bit FAT
+ extended partition */
+ {0xe3, N_("DOS R/O")}, /* DOS R/O or SpeedStor */
+ {0xe4, N_("SpeedStor")}, /* SpeedStor 16-bit FAT extended
+ partition < 1024 cyl. */
+
+ /* Linux https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ */
+ {0xea, N_("Linux extended boot")},
+
+ {0xeb, N_("BeOS fs")},
+ {0xee, N_("GPT")}, /* Intel EFI GUID Partition Table */
+ {0xef, N_("EFI (FAT-12/16/32)")},/* Intel EFI System Partition */
+ {0xf0, N_("Linux/PA-RISC boot")},/* Linux/PA-RISC boot loader */
+ {0xf1, N_("SpeedStor")},
+ {0xf4, N_("SpeedStor")}, /* SpeedStor large partition */
+ {0xf2, N_("DOS secondary")}, /* DOS 3.3+ secondary */
+ {0xfb, N_("VMware VMFS")},
+ {0xfc, N_("VMware VMKCORE")}, /* VMware kernel dump partition */
+ {0xfd, N_("Linux raid autodetect")},/* Linux raid partition with
+ autodetect using persistent
+ superblock */
+ {0xfe, N_("LANstep")}, /* SpeedStor >1024 cyl. or LANstep */
+ {0xff, N_("BBT")}, /* Xenix Bad Block Table */
+
+ { 0, NULL }
diff --git a/src/utils/include/pt-mbr.h b/src/utils/include/pt-mbr.h
new file mode 100644
index 0000000..1a38246
--- /dev/null
+++ b/src/utils/include/pt-mbr.h
@@ -0,0 +1,187 @@
+#ifndef UTIL_LINUX_PT_MBR_H
+#define UTIL_LINUX_PT_MBR_H
+
+#include <assert.h>
+
+struct dos_partition {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char bh, bs, bc; /* begin CHS */
+ unsigned char sys_ind;
+ unsigned char eh, es, ec; /* end CHS */
+ unsigned char start_sect[4];
+ unsigned char nr_sects[4];
+} __attribute__((packed));
+
+#define MBR_PT_OFFSET 0x1be
+#define MBR_PT_BOOTBITS_SIZE 440
+
+static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
+{
+ return (struct dos_partition *)
+ (mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition)));
+}
+
+/* assemble badly aligned little endian integer */
+static inline uint32_t __dos_assemble_4le(const unsigned char *p)
+{
+ uint32_t last_byte = p[3];
+
+ return p[0] | (p[1] << 8) | (p[2] << 16) | (last_byte << 24);
+}
+
+static inline void __dos_store_4le(unsigned char *p, unsigned int val)
+{
+ assert(!(p == NULL));
+ p[0] = (val & 0xff);
+ p[1] = ((val >> 8) & 0xff);
+ p[2] = ((val >> 16) & 0xff);
+ p[3] = ((val >> 24) & 0xff);
+}
+
+static inline unsigned int dos_partition_get_start(struct dos_partition *p)
+{
+ return __dos_assemble_4le(&(p->start_sect[0]));
+}
+
+static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n)
+{
+ __dos_store_4le(p->start_sect, n);
+}
+
+static inline unsigned int dos_partition_get_size(struct dos_partition *p)
+{
+ return __dos_assemble_4le(&(p->nr_sects[0]));
+}
+
+static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n)
+{
+ __dos_store_4le(p->nr_sects, n);
+}
+
+static inline int mbr_is_valid_magic(const unsigned char *mbr)
+{
+ return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0;
+}
+
+static inline void mbr_set_magic(unsigned char *b)
+{
+ b[510] = 0x55;
+ b[511] = 0xaa;
+}
+
+static inline unsigned int mbr_get_id(const unsigned char *mbr)
+{
+ return __dos_assemble_4le(&mbr[440]);
+}
+
+static inline void mbr_set_id(unsigned char *b, unsigned int id)
+{
+ __dos_store_4le(&b[440], id);
+}
+
+enum {
+ MBR_EMPTY_PARTITION = 0x00,
+ MBR_FAT12_PARTITION = 0x01,
+ MBR_XENIX_ROOT_PARTITION = 0x02,
+ MBR_XENIX_USR_PARTITION = 0x03,
+ MBR_FAT16_LESS32M_PARTITION = 0x04,
+ MBR_DOS_EXTENDED_PARTITION = 0x05,
+ MBR_FAT16_PARTITION = 0x06, /* DOS 16-bit >=32M */
+ MBR_HPFS_NTFS_PARTITION = 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+ MBR_AIX_PARTITION = 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ MBR_AIX_BOOTABLE_PARTITION = 0x09, /* AIX data or Coherent */
+ MBR_OS2_BOOTMNGR_PARTITION = 0x0a, /* OS/2 Boot Manager */
+ MBR_W95_FAT32_PARTITION = 0x0b,
+ MBR_W95_FAT32_LBA_PARTITION = 0x0c, /* LBA really is `Extended Int 13h' */
+ MBR_W95_FAT16_LBA_PARTITION = 0x0e,
+ MBR_W95_EXTENDED_PARTITION = 0x0f,
+ MBR_OPUS_PARTITION = 0x10,
+ MBR_HIDDEN_FAT12_PARTITION = 0x11,
+ MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12,
+ MBR_HIDDEN_FAT16_L32M_PARTITION = 0x14,
+ MBR_HIDDEN_FAT16_PARTITION = 0x16,
+ MBR_HIDDEN_HPFS_NTFS_PARTITION = 0x17,
+ MBR_AST_SMARTSLEEP_PARTITION = 0x18,
+ MBR_HIDDEN_W95_FAT32_PARTITION = 0x1b,
+ MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c,
+ MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e,
+ MBR_NEC_DOS_PARTITION = 0x24,
+ MBR_PLAN9_PARTITION = 0x39,
+ MBR_PARTITIONMAGIC_PARTITION = 0x3c,
+ MBR_VENIX80286_PARTITION = 0x40,
+ MBR_PPC_PREP_BOOT_PARTITION = 0x41,
+ MBR_SFS_PARTITION = 0x42,
+ MBR_QNX_4X_PARTITION = 0x4d,
+ MBR_QNX_4X_2ND_PARTITION = 0x4e,
+ MBR_QNX_4X_3RD_PARTITION = 0x4f,
+ MBR_DM_PARTITION = 0x50,
+ MBR_DM6_AUX1_PARTITION = 0x51, /* (or Novell) */
+ MBR_CPM_PARTITION = 0x52, /* CP/M or Microport SysV/AT */
+ MBR_DM6_AUX3_PARTITION = 0x53,
+ MBR_DM6_PARTITION = 0x54,
+ MBR_EZ_DRIVE_PARTITION = 0x55,
+ MBR_GOLDEN_BOW_PARTITION = 0x56,
+ MBR_PRIAM_EDISK_PARTITION = 0x5c,
+ MBR_SPEEDSTOR_PARTITION = 0x61,
+ MBR_GNU_HURD_PARTITION = 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ MBR_UNIXWARE_PARTITION = MBR_GNU_HURD_PARTITION,
+ MBR_NETWARE_286_PARTITION = 0x64,
+ MBR_NETWARE_386_PARTITION = 0x65,
+ MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70,
+ MBR_PC_IX_PARTITION = 0x75,
+ MBR_OLD_MINIX_PARTITION = 0x80, /* Minix 1.4a and earlier */
+ MBR_MINIX_PARTITION = 0x81, /* Minix 1.4b and later */
+ MBR_LINUX_SWAP_PARTITION = 0x82,
+ MBR_SOLARIS_X86_PARTITION = MBR_LINUX_SWAP_PARTITION,
+ MBR_LINUX_DATA_PARTITION = 0x83,
+ MBR_OS2_HIDDEN_DRIVE_PARTITION = 0x84, /* also hibernation MS APM, Intel Rapid Start */
+ MBR_INTEL_HIBERNATION_PARTITION = MBR_OS2_HIDDEN_DRIVE_PARTITION,
+ MBR_LINUX_EXTENDED_PARTITION = 0x85,
+ MBR_NTFS_VOL_SET1_PARTITION = 0x86,
+ MBR_NTFS_VOL_SET2_PARTITION = 0x87,
+ MBR_LINUX_PLAINTEXT_PARTITION = 0x88,
+ MBR_LINUX_LVM_PARTITION = 0x8e,
+ MBR_AMOEBA_PARTITION = 0x93,
+ MBR_AMOEBA_BBT_PARTITION = 0x94, /* (bad block table) */
+ MBR_BSD_OS_PARTITION = 0x9f, /* BSDI */
+ MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0,
+ MBR_FREEBSD_PARTITION = 0xa5, /* various BSD flavours */
+ MBR_OPENBSD_PARTITION = 0xa6,
+ MBR_NEXTSTEP_PARTITION = 0xa7,
+ MBR_DARWIN_UFS_PARTITION = 0xa8,
+ MBR_NETBSD_PARTITION = 0xa9,
+ MBR_DARWIN_BOOT_PARTITION = 0xab,
+ MBR_HFS_HFS_PARTITION = 0xaf,
+ MBR_BSDI_FS_PARTITION = 0xb7,
+ MBR_BSDI_SWAP_PARTITION = 0xb8,
+ MBR_BOOTWIZARD_HIDDEN_PARTITION = 0xbb,
+ MBR_ACRONIS_FAT32LBA_PARTITION = 0xbc, /* Acronis Secure Zone with ipl for loader F11.SYS */
+ MBR_SOLARIS_BOOT_PARTITION = 0xbe,
+ MBR_SOLARIS_PARTITION = 0xbf,
+ MBR_DRDOS_FAT12_PARTITION = 0xc1,
+ MBR_DRDOS_FAT16_L32M_PARTITION = 0xc4,
+ MBR_DRDOS_FAT16_PARTITION = 0xc6,
+ MBR_SYRINX_PARTITION = 0xc7,
+ MBR_NONFS_DATA_PARTITION = 0xda,
+ MBR_CPM_CTOS_PARTITION = 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */
+ MBR_DELL_UTILITY_PARTITION = 0xde, /* Dell PowerEdge Server utilities */
+ MBR_BOOTIT_PARTITION = 0xdf, /* BootIt EMBRM */
+ MBR_DOS_ACCESS_PARTITION = 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */
+ MBR_DOS_RO_PARTITION = 0xe3, /* DOS R/O or SpeedStor */
+ MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */
+ MBR_RUFUS_EXTRA_PARTITION = 0xea, /* Rufus extra partition for alignment */
+ MBR_BEOS_FS_PARTITION = 0xeb,
+ MBR_GPT_PARTITION = 0xee, /* Intel EFI GUID Partition Table */
+ MBR_EFI_SYSTEM_PARTITION = 0xef, /* Intel EFI System Partition */
+ MBR_LINUX_PARISC_BOOT_PARTITION = 0xf0, /* Linux/PA-RISC boot loader */
+ MBR_SPEEDSTOR1_PARTITION = 0xf1,
+ MBR_SPEEDSTOR2_PARTITION = 0xf4, /* SpeedStor large partition */
+ MBR_DOS_SECONDARY_PARTITION = 0xf2, /* DOS 3.3+ secondary */
+ MBR_VMWARE_VMFS_PARTITION = 0xfb,
+ MBR_VMWARE_VMKCORE_PARTITION = 0xfc, /* VMware kernel dump partition */
+ MBR_LINUX_RAID_PARTITION = 0xfd, /* Linux raid partition with autodetect using persistent superblock */
+ MBR_LANSTEP_PARTITION = 0xfe, /* SpeedStor >1024 cyl. or LANstep */
+ MBR_XENIX_BBT_PARTITION = 0xff, /* Xenix Bad Block Table */
+};
+
+#endif /* UTIL_LINUX_PT_MBR_H */
diff --git a/src/utils/include/pt-sgi.h b/src/utils/include/pt-sgi.h
new file mode 100644
index 0000000..6d512ee
--- /dev/null
+++ b/src/utils/include/pt-sgi.h
@@ -0,0 +1,115 @@
+#ifndef UTIL_LINUX_PT_SGI_H
+#define UTIL_LINUX_PT_SGI_H
+
+#include <stdint.h>
+
+#define SGI_LABEL_MAGIC 0x0be5a941
+
+#define SGI_MAXPARTITIONS 16
+#define SGI_MAXVOLUMES 15
+
+/* partition types */
+enum {
+ SGI_TYPE_VOLHDR = 0x00,
+ SGI_TYPE_TRKREPL = 0x01,
+ SGI_TYPE_SECREPL = 0x02,
+ SGI_TYPE_SWAP = 0x03,
+ SGI_TYPE_BSD = 0x04,
+ SGI_TYPE_SYSV = 0x05,
+ SGI_TYPE_ENTIRE_DISK = 0x06,
+ SGI_TYPE_EFS = 0x07,
+ SGI_TYPE_LVOL = 0x08,
+ SGI_TYPE_RLVOL = 0x09,
+ SGI_TYPE_XFS = 0x0a,
+ SGI_TYPE_XFSLOG = 0x0b,
+ SGI_TYPE_XLV = 0x0c,
+ SGI_TYPE_XVM = 0x0d
+};
+
+struct sgi_device_parameter {
+ unsigned char skew;
+ unsigned char gap1;
+ unsigned char gap2;
+ unsigned char sparecyl;
+
+ uint16_t pcylcount;
+ uint16_t head_vol0;
+ uint16_t ntrks; /* tracks in cyl 0 or vol 0 */
+
+ unsigned char cmd_tag_queue_depth;
+ unsigned char unused0;
+
+ uint16_t unused1;
+ uint16_t nsect; /* sectors/tracks in cyl 0 or vol 0 */
+ uint16_t bytes;
+ uint16_t ilfact;
+ uint32_t flags; /* SGI_DEVPARAM_* controller flags */
+ uint32_t datarate;
+ uint32_t retries_on_error;
+ uint32_t ms_per_word;
+ uint16_t xylogics_gap1;
+ uint16_t xylogics_syncdelay;
+ uint16_t xylogics_readdelay;
+ uint16_t xylogics_gap2;
+ uint16_t xylogics_readgate;
+ uint16_t xylogics_writecont;
+} __attribute__((packed));
+
+enum {
+ SGI_DEVPARAM_SECTOR_SLIP = 0x01,
+ SGI_DEVPARAM_SECTOR_FWD = 0x02,
+ SGI_DEVPARAM_TRACK_FWD = 0x04,
+ SGI_DEVPARAM_TRACK_MULTIVOL = 0x08,
+ SGI_DEVPARAM_IGNORE_ERRORS = 0x10,
+ SGI_DEVPARAM_RESEEK = 0x20,
+ SGI_DEVPARAM_CMDTAGQ_ENABLE = 0x40
+};
+
+
+struct sgi_disklabel {
+ uint32_t magic; /* magic number */
+ uint16_t root_part_num; /* # root partition */
+ uint16_t swap_part_num; /* # swap partition */
+ unsigned char boot_file[16]; /* name of boot file */
+
+ struct sgi_device_parameter devparam; /* not used now */
+
+ struct sgi_volume {
+ unsigned char name[8]; /* name of volume */
+ uint32_t block_num; /* logical block number */
+ uint32_t num_bytes; /* how big, in bytes */
+ } __attribute__((packed)) volume[SGI_MAXVOLUMES];
+
+ struct sgi_partition {
+ uint32_t num_blocks; /* size in logical blocks */
+ uint32_t first_block; /* first logical block */
+ uint32_t type; /* type of this partition */
+ } __attribute__((packed)) partitions[SGI_MAXPARTITIONS];
+
+ /* checksum is the 32bit 2's complement sum of the disklabel */
+ uint32_t csum; /* disk label checksum */
+ uint32_t padding; /* padding */
+} __attribute__((packed));
+
+static inline uint32_t sgi_pt_checksum(struct sgi_disklabel *label)
+{
+ int count;
+ uint32_t sum = 0;
+ unsigned char *ptr = (unsigned char *) label;
+
+ count = sizeof(*label) / sizeof(uint32_t);
+ ptr += sizeof(uint32_t) * (count - 1);
+
+ while (count--) {
+ uint32_t val;
+
+ memcpy(&val, ptr, sizeof(uint32_t));
+ sum -= be32_to_cpu(val);
+
+ ptr -= sizeof(uint32_t);
+ }
+
+ return sum;
+}
+
+#endif /* UTIL_LINUX_PT_SGI_H */
diff --git a/src/utils/include/pt-sun.h b/src/utils/include/pt-sun.h
new file mode 100644
index 0000000..8bb5d95
--- /dev/null
+++ b/src/utils/include/pt-sun.h
@@ -0,0 +1,90 @@
+#ifndef UTIL_LINUX_PT_SUN_H
+#define UTIL_LINUX_PT_SUN_H
+
+#include <stdint.h>
+
+#define SUN_LABEL_MAGIC 0xDABE
+
+/* Supported VTOC setting */
+#define SUN_VTOC_SANITY 0x600DDEEE /* magic number */
+#define SUN_VTOC_VERSION 1
+#define SUN_MAXPARTITIONS 8
+
+struct sun_disklabel {
+ unsigned char label_id[128]; /* Informative text string */
+
+ struct sun_vtoc {
+ uint32_t version; /* version */
+ char volume_id[8];/* volume name */
+ uint16_t nparts; /* num of partitions */
+
+ struct sun_info { /* partition information */
+ uint16_t id; /* SUN_TAG_* */
+ uint16_t flags; /* SUN_FLAG_* */
+ } __attribute__ ((packed)) infos[8];
+
+ uint16_t padding; /* padding */
+ uint32_t bootinfo[3]; /* info needed by mboot */
+ uint32_t sanity; /* magic number */
+ uint32_t reserved[10]; /* padding */
+ uint32_t timestamp[8]; /* partition timestamp */
+ } __attribute__ ((packed)) vtoc;
+
+ uint32_t write_reinstruct; /* sectors to skip, writes */
+ uint32_t read_reinstruct; /* sectors to skip, reads */
+ unsigned char spare[148]; /* padding */
+ uint16_t rpm; /* disk rotational speed */
+ uint16_t pcyl; /* physical cylinder count */
+ uint16_t apc; /* extra sects per cylinder */
+ uint16_t obs1;
+ uint16_t obs2;
+ uint16_t intrlv; /* interleave factor */
+ uint16_t ncyl; /* data cylinder count */
+ uint16_t acyl; /* alt. cylinder count */
+ uint16_t nhead; /* tracks per cylinder <---- */
+ uint16_t nsect; /* sectors per track <---- */
+ uint16_t obs3;
+ uint16_t obs4;
+
+ struct sun_partition { /* partitions */
+ uint32_t start_cylinder;
+ uint32_t num_sectors;
+ } __attribute__ ((packed)) partitions[8];
+
+ uint16_t magic; /* magic number */
+ uint16_t csum; /* label xor'd checksum */
+} __attribute__ ((packed));
+
+
+#define SUN_TAG_UNASSIGNED 0x00 /* Unassigned partition */
+#define SUN_TAG_BOOT 0x01 /* Boot partition */
+#define SUN_TAG_ROOT 0x02 /* Root filesystem */
+#define SUN_TAG_SWAP 0x03 /* Swap partition */
+#define SUN_TAG_USR 0x04 /* /usr filesystem */
+#define SUN_TAG_WHOLEDISK 0x05 /* Full-disk slice */
+#define SUN_TAG_STAND 0x06 /* Stand partition */
+#define SUN_TAG_VAR 0x07 /* /var filesystem */
+#define SUN_TAG_HOME 0x08 /* /home filesystem */
+#define SUN_TAG_ALTSCTR 0x09 /* Alt sector partition */
+#define SUN_TAG_CACHE 0x0a /* Cachefs partition */
+#define SUN_TAG_RESERVED 0x0b /* SMI reserved data */
+#define SUN_TAG_LINUX_SWAP 0x82 /* Linux SWAP */
+#define SUN_TAG_LINUX_NATIVE 0x83 /* Linux filesystem */
+#define SUN_TAG_LINUX_LVM 0x8e /* Linux LVM */
+#define SUN_TAG_LINUX_RAID 0xfd /* LInux RAID */
+
+#define SUN_FLAG_UNMNT 0x01 /* Unmountable partition*/
+#define SUN_FLAG_RONLY 0x10 /* Read only */
+
+static inline uint16_t sun_pt_checksum(const struct sun_disklabel *label)
+{
+ const uint16_t *ptr = ((const uint16_t *) (label + 1)) - 1;
+ uint16_t sum;
+
+ for (sum = 0; ptr >= ((const uint16_t *) label);)
+ sum ^= *ptr--;
+
+ return sum;
+}
+
+#endif /* UTIL_LINUX_PT_SUN_H */
diff --git a/src/utils/include/pty-session.h b/src/utils/include/pty-session.h
new file mode 100644
index 0000000..0c9ccc6
--- /dev/null
+++ b/src/utils/include/pty-session.h
@@ -0,0 +1,110 @@
+/*
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com> in Jul 2019
+ */
+#ifndef UTIL_LINUX_PTY_SESSION_H
+#define UTIL_LINUX_PTY_SESSION_H
+
+#include <pty.h>
+#include <termios.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <sys/signalfd.h>
+
+/*
+ * Callbacks -- the first argument is always callback data, see
+ * ul_pty_set_callback_data().
+ */
+struct ul_pty_callbacks {
+ /*
+ * Optional. Executed on SIGCHLD when ssi_code is EXITED, KILLED or
+ * DUMPED; The callback has to call ul_pty_set_child(pty, (pid_t) -1)
+ * if child is no more alive.
+ */
+ void (*child_wait)(void *, pid_t);
+
+ /*
+ * Used when child_wait() undefined to informa about child status
+ */
+ void (*child_die)(void *, pid_t, int);
+
+ /*
+ * Executed on SIGCHLD when ssi_status is SIGSTOP
+ */
+ void (*child_sigstop)(void *, pid_t);
+
+ /*
+ * Executed in master loop before ul_pty enter poll() and in time set by
+ * ul_pty_set_mainloop_time(). The callback is no used when time is not set.
+ */
+ int (*mainloop)(void *);
+
+ /*
+ * Executed on master or stdin activity, arguments:
+ * 2nd - file descriptor
+ * 3rd - buffer with data
+ * 4th - size of the data
+ */
+ int (*log_stream_activity)(void *, int, char *, size_t);
+
+ /*
+ * Executed on signal, arguments:
+ * 2nd - signal info
+ * 3rd - NULL or signal specific data (e.g. struct winsize on SIGWINCH
+ */
+ int (*log_signal)(void *, struct signalfd_siginfo *, void *);
+
+ /*
+ * Executed on SIGUSR1
+ */
+ int (*flush_logs)(void *);
+};
+
+struct ul_pty {
+ struct termios stdin_attrs; /* stdin and slave terminal runtime attributes */
+ int master; /* parent side */
+ int slave; /* child side */
+ int sigfd; /* signalfd() */
+ int poll_timeout;
+ struct winsize win; /* terminal window size */
+ sigset_t orgsig; /* original signal mask */
+
+ int delivered_signal;
+
+ struct ul_pty_callbacks callbacks;
+ void *callback_data;
+
+ pid_t child;
+
+ struct timeval next_callback_time;
+
+ unsigned int isterm:1, /* is stdin terminal? */
+ slave_echo:1; /* keep ECHO on pty slave */
+};
+
+void ul_pty_init_debug(int mask);
+struct ul_pty *ul_new_pty(int is_stdin_tty);
+void ul_free_pty(struct ul_pty *pty);
+
+void ul_pty_slave_echo(struct ul_pty *pty, int enable);
+int ul_pty_get_delivered_signal(struct ul_pty *pty);
+
+void ul_pty_set_callback_data(struct ul_pty *pty, void *data);
+void ul_pty_set_child(struct ul_pty *pty, pid_t child);
+
+struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty);
+int ul_pty_is_running(struct ul_pty *pty);
+int ul_pty_setup(struct ul_pty *pty);
+void ul_pty_cleanup(struct ul_pty *pty);
+void ul_pty_init_slave(struct ul_pty *pty);
+int ul_pty_proxy_master(struct ul_pty *pty);
+
+void ul_pty_set_mainloop_time(struct ul_pty *pty, struct timeval *tv);
+int ul_pty_get_childfd(struct ul_pty *pty);
+void ul_pty_wait_for_child(struct ul_pty *pty);
+pid_t ul_pty_get_child(struct ul_pty *pty);
+void ul_pty_write_eof_to_child(struct ul_pty *pty);
+
+#endif /* UTIL_LINUX_PTY_H */
diff --git a/src/utils/include/pwdutils.h b/src/utils/include/pwdutils.h
new file mode 100644
index 0000000..b58268d
--- /dev/null
+++ b/src/utils/include/pwdutils.h
@@ -0,0 +1,14 @@
+#ifndef UTIL_LINUX_PWDUTILS_H
+#define UTIL_LINUX_PWDUTILS_H
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+extern struct passwd *xgetpwnam(const char *username, char **pwdbuf);
+extern struct group *xgetgrnam(const char *groupname, char **grpbuf);
+extern struct passwd *xgetpwuid(uid_t uid, char **pwdbuf);
+extern char *xgetlogin(void);
+
+#endif /* UTIL_LINUX_PWDUTILS_H */
+
diff --git a/src/utils/include/randutils.h b/src/utils/include/randutils.h
new file mode 100644
index 0000000..86e35f3
--- /dev/null
+++ b/src/utils/include/randutils.h
@@ -0,0 +1,17 @@
+#ifndef UTIL_LINUX_RANDUTILS
+#define UTIL_LINUX_RANDUTILS
+
+#ifdef HAVE_SRANDOM
+#define srand(x) srandom(x)
+#define rand() random()
+#endif
+
+/* rand() based */
+extern int rand_get_number(int low_n, int high_n);
+
+/* /dev/urandom based with fallback to rand() */
+extern int random_get_fd(void);
+extern void random_get_bytes(void *buf, size_t nbytes);
+extern const char *random_tell_source(void);
+
+#endif
diff --git a/src/utils/include/rpmatch.h b/src/utils/include/rpmatch.h
new file mode 100644
index 0000000..f64d52e
--- /dev/null
+++ b/src/utils/include/rpmatch.h
@@ -0,0 +1,13 @@
+#ifndef UTIL_LINUX_RPMATCH_H
+#define UTIL_LINUX_RPMATCH_H
+
+#ifndef HAVE_RPMATCH
+#define rpmatch(r) \
+ (*r == 'y' || *r == 'Y' ? 1 : *r == 'n' || *r == 'N' ? 0 : -1)
+#endif
+
+#define RPMATCH_YES 1
+#define RPMATCH_NO 0
+#define RPMATCH_INVALID -1
+
+#endif /* UTIL_LINUX_RPMATCH_H */
diff --git a/src/utils/include/setproctitle.h b/src/utils/include/setproctitle.h
new file mode 100644
index 0000000..70a9efa
--- /dev/null
+++ b/src/utils/include/setproctitle.h
@@ -0,0 +1,7 @@
+#ifndef UTIL_LINUX_SETPROCTITLE_H
+#define UTIL_LINUX_SETPROCTITLE_H
+
+extern void initproctitle (int argc, char **argv);
+extern void setproctitle (const char *prog, const char *txt);
+
+#endif
diff --git a/src/utils/include/sha1.h b/src/utils/include/sha1.h
new file mode 100644
index 0000000..62af1da
--- /dev/null
+++ b/src/utils/include/sha1.h
@@ -0,0 +1,27 @@
+#ifndef UTIL_LINUX_SHA1_H
+#define UTIL_LINUX_SHA1_H
+
+/*
+ SHA-1 in C
+ By Steve Reid <steve@edmweb.com>
+ 100% Public Domain
+ */
+
+#include "stdint.h"
+
+#define UL_SHA1LENGTH 20
+
+typedef struct
+{
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} UL_SHA1_CTX;
+
+void ul_SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
+void ul_SHA1Init(UL_SHA1_CTX *context);
+void ul_SHA1Update(UL_SHA1_CTX *context, const unsigned char *data, uint32_t len);
+void ul_SHA1Final(unsigned char digest[UL_SHA1LENGTH], UL_SHA1_CTX *context);
+void ul_SHA1(char *hash_out, const char *str, unsigned len);
+
+#endif /* UTIL_LINUX_SHA1_H */
diff --git a/src/utils/include/signames.h b/src/utils/include/signames.h
new file mode 100644
index 0000000..a4fd1bc
--- /dev/null
+++ b/src/utils/include/signames.h
@@ -0,0 +1,8 @@
+#ifndef SIGNAMES_H
+#define SIGNAMES_H
+
+int signame_to_signum(const char *sig);
+const char *signum_to_signame(int signum);
+int get_signame_by_idx(size_t idx, const char **signame, int *signum);
+
+#endif /* SIGNAMES_H */
diff --git a/src/utils/include/statfs_magic.h b/src/utils/include/statfs_magic.h
new file mode 100644
index 0000000..b6b0225
--- /dev/null
+++ b/src/utils/include/statfs_magic.h
@@ -0,0 +1,100 @@
+#ifndef UTIL_LINUX_STATFS_MAGIC_H
+#define UTIL_LINUX_STATFS_MAGIC_H
+
+#include <sys/statfs.h>
+
+/*
+ * If possible then don't depend on internal libc __SWORD_TYPE type.
+ */
+#ifdef __GNUC__
+#define F_TYPE_EQUAL(a, b) (a == (__typeof__(a)) b)
+#else
+#define F_TYPE_EQUAL(a, b) (a == (__SWORD_TYPE) b)
+#endif
+
+/*
+ * Unfortunately, Linux kernel header file <linux/magic.h> is incomplete
+ * mess and kernel returns by statfs f_type many numbers that are nowhere
+ * specified (in API).
+ *
+ * This is collection of the magic numbers.
+ */
+#define STATFS_ADFS_MAGIC 0xadf5
+#define STATFS_AFFS_MAGIC 0xadff
+#define STATFS_AFS_MAGIC 0x5346414F
+#define STATFS_AUTOFS_MAGIC 0x0187
+#define STATFS_BDEVFS_MAGIC 0x62646576
+#define STATFS_BEFS_MAGIC 0x42465331
+#define STATFS_BFS_MAGIC 0x1BADFACE
+#define STATFS_BINFMTFS_MAGIC 0x42494e4d
+#define STATFS_BTRFS_MAGIC 0x9123683E
+#define STATFS_CEPH_MAGIC 0x00c36400
+#define STATFS_CGROUP_MAGIC 0x27e0eb
+#define STATFS_CGROUP2_MAGIC 0x63677270
+#define STATFS_CIFS_MAGIC 0xff534d42
+#define STATFS_CODA_MAGIC 0x73757245
+#define STATFS_CONFIGFS_MAGIC 0x62656570
+#define STATFS_CRAMFS_MAGIC 0x28cd3d45
+#define STATFS_DEBUGFS_MAGIC 0x64626720
+#define STATFS_DEVPTS_MAGIC 0x1cd1
+#define STATFS_ECRYPTFS_MAGIC 0xf15f
+#define STATFS_EFIVARFS_MAGIC 0xde5e81e4
+#define STATFS_EFS_MAGIC 0x414A53
+#define STATFS_EXOFS_MAGIC 0x5DF5
+#define STATFS_EXT2_MAGIC 0xEF53
+#define STATFS_EXT3_MAGIC 0xEF53
+#define STATFS_EXT4_MAGIC 0xEF53
+#define STATFS_F2FS_MAGIC 0xF2F52010
+#define STATFS_FUSE_MAGIC 0x65735546
+#define STATFS_FUTEXFS_MAGIC 0xBAD1DEA
+#define STATFS_GFS2_MAGIC 0x01161970
+#define STATFS_HFSPLUS_MAGIC 0x482b
+#define STATFS_HOSTFS_MAGIC 0x00c0ffee
+#define STATFS_HPFS_MAGIC 0xf995e849
+#define STATFS_HPPFS_MAGIC 0xb00000ee
+#define STATFS_HUGETLBFS_MAGIC 0x958458f6
+#define STATFS_ISOFS_MAGIC 0x9660
+#define STATFS_JFFS2_MAGIC 0x72b6
+#define STATFS_JFS_MAGIC 0x3153464a
+#define STATFS_LOGFS_MAGIC 0xc97e8168
+#define STATFS_MINIX2_MAGIC 0x2468
+#define STATFS_MINIX2_MAGIC2 0x2478
+#define STATFS_MINIX3_MAGIC 0x4d5a
+#define STATFS_MINIX_MAGIC 0x137F
+#define STATFS_MINIX_MAGIC2 0x138F
+#define STATFS_MQUEUE_MAGIC 0x19800202
+#define STATFS_MSDOS_MAGIC 0x4d44
+#define STATFS_NCP_MAGIC 0x564c
+#define STATFS_NFS_MAGIC 0x6969
+#define STATFS_NILFS_MAGIC 0x3434
+#define STATFS_NTFS_MAGIC 0x5346544e
+#define STATFS_OCFS2_MAGIC 0x7461636f
+#define STATFS_OMFS_MAGIC 0xC2993D87
+#define STATFS_OPENPROMFS_MAGIC 0x9fa1
+#define STATFS_PIPEFS_MAGIC 0x50495045
+#define STATFS_PROC_MAGIC 0x9fa0
+#define STATFS_PSTOREFS_MAGIC 0x6165676C
+#define STATFS_QNX4_MAGIC 0x002f
+#define STATFS_QNX6_MAGIC 0x68191122
+#define STATFS_RAMFS_MAGIC 0x858458f6
+#define STATFS_REISERFS_MAGIC 0x52654973
+#define STATFS_ROMFS_MAGIC 0x7275
+#define STATFS_SECURITYFS_MAGIC 0x73636673
+#define STATFS_SELINUXFS_MAGIC 0xf97cff8c
+#define STATFS_SMACKFS_MAGIC 0x43415d53
+#define STATFS_SMB_MAGIC 0x517B
+#define STATFS_SOCKFS_MAGIC 0x534F434B
+#define STATFS_SQUASHFS_MAGIC 0x73717368
+#define STATFS_SYSFS_MAGIC 0x62656572
+#define STATFS_TMPFS_MAGIC 0x01021994
+#define STATFS_UBIFS_MAGIC 0x24051905
+#define STATFS_UDF_MAGIC 0x15013346
+#define STATFS_UFS2_MAGIC 0x19540119
+#define STATFS_UFS_MAGIC 0x00011954
+#define STATFS_V9FS_MAGIC 0x01021997
+#define STATFS_VXFS_MAGIC 0xa501FCF5
+#define STATFS_XENFS_MAGIC 0xabba1974
+#define STATFS_XFS_MAGIC 0x58465342
+
+#endif /* UTIL_LINUX_STATFS_MAGIC_H */
+
diff --git a/src/utils/include/strutils.h b/src/utils/include/strutils.h
new file mode 100644
index 0000000..4b3182f
--- /dev/null
+++ b/src/utils/include/strutils.h
@@ -0,0 +1,333 @@
+#ifndef UTIL_LINUX_STRUTILS
+#define UTIL_LINUX_STRUTILS
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* initialize a custom exit code for all *_or_err functions */
+extern void strutils_set_exitcode(int exit_code);
+
+extern int parse_size(const char *str, uintmax_t *res, int *power);
+extern int strtosize(const char *str, uintmax_t *res);
+extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
+
+extern int16_t strtos16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtox16_or_err(const char *str, const char *errmesg);
+
+extern int32_t strtos32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtox32_or_err(const char *str, const char *errmesg);
+
+extern int64_t strtos64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtox64_or_err(const char *str, const char *errmesg);
+
+extern double strtod_or_err(const char *str, const char *errmesg);
+
+extern long strtol_or_err(const char *str, const char *errmesg);
+extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
+
+extern void strtotimeval_or_err(const char *str, struct timeval *tv,
+ const char *errmesg);
+
+extern int isdigit_strend(const char *str, const char **end);
+#define isdigit_string(_s) isdigit_strend(_s, NULL)
+
+extern int isxdigit_strend(const char *str, const char **end);
+#define isxdigit_string(_s) isxdigit_strend(_s, NULL)
+
+
+extern int parse_switch(const char *arg, const char *errmesg, ...);
+
+#ifndef HAVE_MEMPCPY
+extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
+#endif
+#ifndef HAVE_STRNLEN
+extern size_t strnlen(const char *s, size_t maxlen);
+#endif
+#ifndef HAVE_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#endif
+#ifndef HAVE_STRNCHR
+extern char *strnchr(const char *s, size_t maxlen, int c);
+#endif
+
+/* caller guarantees n > 0 */
+static inline void xstrncpy(char *dest, const char *src, size_t n)
+{
+ strncpy(dest, src, n-1);
+ dest[n-1] = 0;
+}
+
+/* This is like strncpy(), but based on memcpy(), so compilers and static
+ * analyzers do not complain when sizeof(destination) is the same as 'n' and
+ * result is not terminated by zero.
+ *
+ * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
+ * where string terminator is optional.
+ */
+static inline void *str2memcpy(void *dest, const char *src, size_t n)
+{
+ size_t bytes = strlen(src) + 1;
+
+ if (bytes > n)
+ bytes = n;
+
+ memcpy(dest, src, bytes);
+ return dest;
+}
+
+static inline char *mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
+{
+ if (n + 1 > nmax)
+ n = nmax - 1;
+
+ memcpy(dest, src, n);
+ dest[nmax-1] = '\0';
+ return dest;
+}
+
+/* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str.
+ * The @str is not modified if reallocation failed (like classic realloc()).
+ */
+static inline char * __attribute__((warn_unused_result))
+strrealloc(char *str, const char *newstr)
+{
+ size_t nsz, osz;
+
+ if (!str)
+ return newstr ? strdup(newstr) : NULL;
+ if (!newstr)
+ return NULL;
+
+ osz = strlen(str);
+ nsz = strlen(newstr);
+
+ if (nsz > osz)
+ str = realloc(str, nsz + 1);
+ if (str)
+ memcpy(str, newstr, nsz + 1);
+ return str;
+}
+
+/* Copy string @str to struct @stru to member addressed by @offset */
+static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
+{
+ char **o;
+ char *p = NULL;
+
+ if (!stru)
+ return -EINVAL;
+
+ o = (char **) ((char *) stru + offset);
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(*o);
+ *o = p;
+ return 0;
+}
+
+/* Copy string __str to struct member _m of the struct _s */
+#define strdup_to_struct_member(_s, _m, _str) \
+ strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
+
+/* Copy string addressed by @offset between two structs */
+static inline int strdup_between_offsets(void *stru_dst, void *stru_src, size_t offset)
+{
+ char **src;
+ char **dst;
+ char *p = NULL;
+
+ if (!stru_src || !stru_dst)
+ return -EINVAL;
+
+ src = (char **) ((char *) stru_src + offset);
+ dst = (char **) ((char *) stru_dst + offset);
+
+ if (*src) {
+ p = strdup(*src);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(*dst);
+ *dst = p;
+ return 0;
+}
+
+/* Copy string addressed by struct member between two instances of the same
+ * struct type */
+#define strdup_between_structs(_dst, _src, _m) \
+ strdup_between_offsets((void *)_dst, (void *)_src, offsetof(__typeof__(*(_src)), _m))
+
+
+extern char *xstrmode(mode_t mode, char *str);
+
+/* Options for size_to_human_string() */
+enum
+{
+ SIZE_SUFFIX_1LETTER = 0,
+ SIZE_SUFFIX_3LETTER = (1 << 0),
+ SIZE_SUFFIX_SPACE = (1 << 1),
+ SIZE_DECIMAL_2DIGITS = (1 << 2)
+};
+
+extern char *size_to_human_string(int options, uint64_t bytes);
+
+extern int string_to_idarray(const char *list, int ary[], size_t arysz,
+ int (name2id)(const char *, size_t));
+extern int string_add_to_idarray(const char *list, int ary[],
+ size_t arysz, size_t *ary_pos,
+ int (name2id)(const char *, size_t));
+
+extern int string_to_bitarray(const char *list, char *ary,
+ int (*name2bit)(const char *, size_t));
+
+extern int string_to_bitmask(const char *list,
+ unsigned long *mask,
+ long (*name2flag)(const char *, size_t));
+extern int parse_range(const char *str, int *lower, int *upper, int def);
+
+extern int streq_paths(const char *a, const char *b);
+
+/*
+ * Match string beginning.
+ */
+static inline const char *startswith(const char *s, const char *prefix)
+{
+ size_t sz = prefix ? strlen(prefix) : 0;
+
+ if (s && sz && strncmp(s, prefix, sz) == 0)
+ return s + sz;
+ return NULL;
+}
+
+/*
+ * Case insensitive match string beginning.
+ */
+static inline const char *startswith_no_case(const char *s, const char *prefix)
+{
+ size_t sz = prefix ? strlen(prefix) : 0;
+
+ if (s && sz && strncasecmp(s, prefix, sz) == 0)
+ return s + sz;
+ return NULL;
+}
+
+/*
+ * Match string ending.
+ */
+static inline const char *endswith(const char *s, const char *postfix)
+{
+ size_t sl = s ? strlen(s) : 0;
+ size_t pl = postfix ? strlen(postfix) : 0;
+
+ if (pl == 0)
+ return s + sl;
+ if (sl < pl)
+ return NULL;
+ if (memcmp(s + sl - pl, postfix, pl) != 0)
+ return NULL;
+ return s + sl - pl;
+}
+
+/*
+ * Skip leading white space.
+ */
+static inline const char *skip_space(const char *p)
+{
+ while (isspace(*p))
+ ++p;
+ return p;
+}
+
+static inline const char *skip_blank(const char *p)
+{
+ while (isblank(*p))
+ ++p;
+ return p;
+}
+
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t rtrim_whitespace(unsigned char *str)
+{
+ size_t i;
+
+ if (!str)
+ return 0;
+ i = strlen((char *) str);
+ while (i) {
+ i--;
+ if (!isspace(str[i])) {
+ i++;
+ break;
+ }
+ }
+ str[i] = '\0';
+ return i;
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t ltrim_whitespace(unsigned char *str)
+{
+ size_t len;
+ unsigned char *p;
+
+ if (!str)
+ return 0;
+ for (p = str; *p && isspace(*p); p++);
+
+ len = strlen((char *) p);
+
+ if (p > str)
+ memmove(str, p, len + 1);
+
+ return len;
+}
+
+static inline void strrep(char *s, int find, int replace)
+{
+ while (s && *s && (s = strchr(s, find)) != NULL)
+ *s++ = replace;
+}
+
+static inline void strrem(char *s, int rem)
+{
+ char *p;
+
+ if (!s)
+ return;
+ for (p = s; *s; s++) {
+ if (*s != rem)
+ *p++ = *s;
+ }
+ *p = '\0';
+}
+
+extern char *strnappend(const char *s, const char *suffix, size_t b);
+extern char *strappend(const char *s, const char *suffix);
+extern char *strfappend(const char *s, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 2, 0)));
+extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
+
+extern int skip_fline(FILE *fp);
+
+#endif
diff --git a/src/utils/include/strv.h b/src/utils/include/strv.h
new file mode 100644
index 0000000..260ad12
--- /dev/null
+++ b/src/utils/include/strv.h
@@ -0,0 +1,55 @@
+#ifndef UTIL_LINUX_STRV
+#define UTIL_LINUX_STRV
+
+#include <stdarg.h>
+
+#include "c.h"
+
+char **strv_free(char **l);
+void strv_clear(char **l);
+char **strv_copy(char * const *l);
+unsigned strv_length(char * const *l);
+
+int strv_extend_strv(char ***a, char **b);
+int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
+int strv_extend(char ***l, const char *value);
+int strv_extendv(char ***l, const char *format, va_list ap);
+int strv_extendf(char ***l, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 2, 0)));
+int strv_push(char ***l, char *value);
+int strv_push_prepend(char ***l, char *value);
+int strv_consume(char ***l, char *value);
+int strv_consume_prepend(char ***l, char *value);
+
+char **strv_remove(char **l, const char *s);
+
+char **strv_new(const char *x, ...);
+char **strv_new_ap(const char *x, va_list ap);
+
+static inline const char* STRV_IFNOTNULL(const char *x) {
+ return x ? x : (const char *) -1;
+}
+
+static inline int strv_isempty(char * const *l) {
+ return !l || !*l;
+}
+
+char **strv_split(const char *s, const char *separator);
+char *strv_join(char **l, const char *separator);
+
+#define STRV_FOREACH(s, l) \
+ for ((s) = (l); (s) && *(s); (s)++)
+
+#define STRV_FOREACH_BACKWARDS(s, l) \
+ STRV_FOREACH(s, l) \
+ ; \
+ for ((s)--; (l) && ((s) >= (l)); (s)--)
+
+
+#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
+
+char **strv_reverse(char **l);
+
+#endif /* UTIL_LINUX_STRV */
+
+
diff --git a/src/utils/include/swapheader.h b/src/utils/include/swapheader.h
new file mode 100644
index 0000000..3fce0d0
--- /dev/null
+++ b/src/utils/include/swapheader.h
@@ -0,0 +1,23 @@
+#ifndef _SWAPHEADER_H
+#define _SWAPHEADER_H
+
+#define SWAP_VERSION 1
+#define SWAP_UUID_LENGTH 16
+#define SWAP_LABEL_LENGTH 16
+#define SWAP_SIGNATURE "SWAPSPACE2"
+#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
+
+#include <stdint.h>
+
+struct swap_header_v1_2 {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ uint32_t version;
+ uint32_t last_page;
+ uint32_t nr_badpages;
+ unsigned char uuid[SWAP_UUID_LENGTH];
+ char volume_name[SWAP_LABEL_LENGTH];
+ uint32_t padding[117];
+ uint32_t badpages[1];
+};
+
+#endif /* _SWAPHEADER_H */
diff --git a/src/utils/include/swapprober.h b/src/utils/include/swapprober.h
new file mode 100644
index 0000000..5107700
--- /dev/null
+++ b/src/utils/include/swapprober.h
@@ -0,0 +1,9 @@
+#ifndef UTIL_LINUX_SWAP_PROBER_H
+#define UTIL_LINUX_SWAP_PROBER_H
+
+#include <blkid.h>
+
+blkid_probe get_swap_prober(const char *devname);
+
+#endif /* UTIL_LINUX_SWAP_PROBER_H */
+
diff --git a/src/utils/include/sysfs.h b/src/utils/include/sysfs.h
new file mode 100644
index 0000000..dcd2a14
--- /dev/null
+++ b/src/utils/include/sysfs.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ */
+#ifndef UTIL_LINUX_SYSFS_H
+#define UTIL_LINUX_SYSFS_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <dirent.h>
+
+#include "path.h"
+
+/**
+ * sysfs_devname_sys_to_dev:
+ * @name: devname to be converted in place
+ *
+ * Linux kernel linux/drivers/base/core.c: device_get_devnode()
+ * defines a replacement of '!' in the /sys device name by '/' in the
+ * /dev device name. This helper replaces all occurrences of '!' in
+ * @name by '/' to convert from /sys to /dev.
+ */
+static inline void sysfs_devname_sys_to_dev(char *name)
+{
+ char *c;
+
+ if (name)
+ while ((c = strchr(name, '!')))
+ c[0] = '/';
+}
+
+/**
+ * sysfs_devname_dev_to_sys:
+ * @name: devname to be converted in place
+ *
+ * See sysfs_devname_sys_to_dev().
+ */
+static inline void sysfs_devname_dev_to_sys(char *name)
+{
+ char *c;
+
+ if (name)
+ while ((c = strchr(name, '/')))
+ c[0] = '!';
+}
+
+struct sysfs_blkdev {
+ dev_t devno;
+ struct path_cxt *parent;
+
+ unsigned int scsi_host,
+ scsi_channel,
+ scsi_target,
+ scsi_lun;
+
+ unsigned int has_hctl : 1,
+ hctl_error : 1 ;
+};
+
+void ul_sysfs_init_debug(void);
+
+struct path_cxt *ul_new_sysfs_path(dev_t devno, struct path_cxt *parent, const char *prefix);
+int sysfs_blkdev_init_path(struct path_cxt *pc, dev_t devno, struct path_cxt *parent);
+
+int sysfs_blkdev_set_parent(struct path_cxt *pc, struct path_cxt *parent);
+struct path_cxt *sysfs_blkdev_get_parent(struct path_cxt *pc);
+
+char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz);
+int sysfs_blkdev_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name);
+int sysfs_blkdev_count_partitions(struct path_cxt *pc, const char *devname);
+dev_t sysfs_blkdev_partno_to_devno(struct path_cxt *pc, int partno);
+char *sysfs_blkdev_get_slave(struct path_cxt *pc);
+char *sysfs_blkdev_get_path(struct path_cxt *pc, char *buf, size_t bufsiz);
+dev_t sysfs_blkdev_get_devno(struct path_cxt *pc);
+
+char *sysfs_blkdev_get_devchain(struct path_cxt *pc, char *buf, size_t bufsz);
+int sysfs_blkdev_next_subsystem(struct path_cxt *pc __attribute__((unused)), char *devchain, char **subsys);
+
+int sysfs_blkdev_is_hotpluggable(struct path_cxt *pc);
+int sysfs_blkdev_get_wholedisk( struct path_cxt *pc,
+ char *diskname,
+ size_t len,
+ dev_t *diskdevno);
+
+int sysfs_devno_to_wholedisk(dev_t dev, char *diskname,
+ size_t len, dev_t *diskdevno);
+int sysfs_devno_is_dm_private(dev_t devno, char **uuid);
+int sysfs_devno_is_wholedisk(dev_t devno);
+
+dev_t sysfs_devname_to_devno(const char *name);
+dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent);
+int sysfs_devname_is_hidden(const char *prefix, const char *name);
+
+char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz);
+char *sysfs_devno_to_devname(dev_t devno, char *buf, size_t bufsiz);
+int sysfs_devno_count_partitions(dev_t devno);
+
+int sysfs_blkdev_scsi_get_hctl(struct path_cxt *pc, int *h, int *c, int *t, int *l);
+char *sysfs_blkdev_scsi_host_strdup_attribute(struct path_cxt *pc,
+ const char *type, const char *attr);
+int sysfs_blkdev_scsi_host_is(struct path_cxt *pc, const char *type);
+int sysfs_blkdev_scsi_has_attribute(struct path_cxt *pc, const char *attr);
+int sysfs_blkdev_scsi_path_contains(struct path_cxt *pc, const char *pattern);
+
+
+#endif /* UTIL_LINUX_SYSFS_H */
diff --git a/src/utils/include/timer.h b/src/utils/include/timer.h
new file mode 100644
index 0000000..70da1ba
--- /dev/null
+++ b/src/utils/include/timer.h
@@ -0,0 +1,22 @@
+#ifndef UTIL_LINUX_TIMER_H
+#define UTIL_LINUX_TIMER_H
+
+#include <signal.h>
+#include <sys/time.h>
+
+#ifdef HAVE_TIMER_CREATE
+struct ul_timer {
+ timer_t t_id;
+};
+#else
+struct ul_timer {
+ struct itimerval old_timer;
+ struct sigaction old_sa;
+};
+#endif
+
+extern int setup_timer(struct ul_timer *timer, struct itimerval *timeout,
+ void (*timeout_handler)(int, siginfo_t *, void *));
+extern void cancel_timer(struct ul_timer *timer);
+
+#endif /* UTIL_LINUX_TIMER_H */
diff --git a/src/utils/include/timeutils.h b/src/utils/include/timeutils.h
new file mode 100644
index 0000000..e452e55
--- /dev/null
+++ b/src/utils/include/timeutils.h
@@ -0,0 +1,92 @@
+/***
+ First set of functions in this file are part of systemd, and were
+ copied to util-linux at August 2013.
+
+ Copyright 2010 Lennart Poettering
+ Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+#ifndef UTIL_LINUX_TIME_UTIL_H
+#define UTIL_LINUX_TIME_UTIL_H
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <sys/time.h>
+
+typedef uint64_t usec_t;
+typedef uint64_t nsec_t;
+
+#define MSEC_PER_SEC 1000ULL
+#define USEC_PER_SEC 1000000ULL
+#define USEC_PER_MSEC 1000ULL
+#define NSEC_PER_SEC 1000000000ULL
+#define NSEC_PER_MSEC 1000000ULL
+#define NSEC_PER_USEC 1000ULL
+
+#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC)
+#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC)
+#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
+#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE)
+#define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
+#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR)
+#define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
+#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY)
+#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC)
+#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC)
+#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC)
+#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC)
+
+#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */
+#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
+#define FORMAT_TIMESPAN_MAX 64
+
+int parse_timestamp(const char *t, usec_t *usec);
+int get_gmtoff(const struct tm *tp);
+
+/* flags and masks for strxxx_iso() functions */
+enum {
+ ISO_DATE = (1 << 0),
+ ISO_TIME = (1 << 1),
+ ISO_TIMEZONE = (1 << 2),
+ ISO_DOTUSEC = (1 << 3),
+ ISO_COMMAUSEC = (1 << 4),
+ ISO_T = (1 << 5),
+ ISO_GMTIME = (1 << 6),
+ ISO_TIMESTAMP = ISO_DATE | ISO_TIME | ISO_TIMEZONE,
+ ISO_TIMESTAMP_T = ISO_TIMESTAMP | ISO_T,
+ ISO_TIMESTAMP_DOT = ISO_TIMESTAMP | ISO_DOTUSEC,
+ ISO_TIMESTAMP_DOT_T = ISO_TIMESTAMP_DOT | ISO_T,
+ ISO_TIMESTAMP_COMMA = ISO_TIMESTAMP | ISO_COMMAUSEC,
+ ISO_TIMESTAMP_COMMA_T = ISO_TIMESTAMP_COMMA | ISO_T,
+ ISO_TIMESTAMP_COMMA_G = ISO_TIMESTAMP_COMMA | ISO_GMTIME,
+ ISO_TIMESTAMP_COMMA_GT = ISO_TIMESTAMP_COMMA_G | ISO_T
+};
+
+#define CTIME_BUFSIZ 26
+#define ISO_BUFSIZ 42
+
+int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz);
+int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz);
+int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz);
+
+#define UL_SHORTTIME_THISYEAR_HHMM (1 << 1)
+
+int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, size_t bufsz);
+
+#ifndef HAVE_TIMEGM
+extern time_t timegm(struct tm *tm);
+#endif
+
+#endif /* UTIL_LINUX_TIME_UTIL_H */
diff --git a/src/utils/include/ttyutils.h b/src/utils/include/ttyutils.h
new file mode 100644
index 0000000..f164a58
--- /dev/null
+++ b/src/utils/include/ttyutils.h
@@ -0,0 +1,205 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#ifndef UTIL_LINUX_TTYUTILS_H
+#define UTIL_LINUX_TTYUTILS_H
+
+#include <stdlib.h>
+#include <termios.h>
+#include <limits.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_TTYDEFAULTS_H
+#include <sys/ttydefaults.h>
+#endif
+
+/* Some shorthands for control characters. */
+#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */
+#define CR CTL('M') /* carriage return */
+#define NL CTL('J') /* line feed */
+#define BS CTL('H') /* back space */
+#define DEL CTL('?') /* delete */
+
+/* Defaults for line-editing etc. characters; you may want to change these. */
+#define DEF_ERASE DEL /* default erase character */
+#define DEF_INTR CTL('C') /* default interrupt character */
+#define DEF_QUIT CTL('\\') /* default quit char */
+#define DEF_KILL CTL('U') /* default kill char */
+#define DEF_EOF CTL('D') /* default EOF char */
+#define DEF_EOL 0
+#define DEF_SWITCH 0 /* default switch char */
+
+/* Fallback for termios->c_cc[] */
+#ifndef CREPRINT
+# define CREPRINT ('r' & 037)
+#endif
+#ifndef CDISCARD
+# define CDISCARD ('o' & 037)
+#endif
+
+/* Default termios->iflag */
+#ifndef TTYDEF_IFLAG
+# define TTYDEF_IFLAG (BRKINT | ICRNL | IMAXBEL | IXON | IXANY)
+#endif
+
+/* Default termios->oflag */
+#ifndef TTYDEF_OFLAG
+# define TTYDEF_OFLAG (OPOST | ONLCR /*| OXTABS*/)
+#endif
+
+/* Default termios->lflag */
+#ifndef TTYDEF_LFLAG
+# define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL)
+#endif
+
+/* Default termios->cflag */
+#ifndef TTYDEF_CFLAG
+# define TTYDEF_CFLAG (CREAD | CS8 | HUPCL)
+#endif
+
+/* Storage for things detected while the login name was read. */
+struct chardata {
+ int erase; /* erase character */
+ int kill; /* kill character */
+ int eol; /* end-of-line character */
+ int parity; /* what parity did we see */
+ int capslock; /* upper case without lower case */
+};
+
+#define INIT_CHARDATA(ptr) do { \
+ (ptr)->erase = DEF_ERASE; \
+ (ptr)->kill = DEF_KILL; \
+ (ptr)->eol = CTRL('r'); \
+ (ptr)->parity = 0; \
+ (ptr)->capslock = 0; \
+ } while (0)
+
+extern int get_terminal_dimension(int *cols, int *lines);
+extern int get_terminal_width(int default_width);
+extern int get_terminal_type(const char **type);
+extern int get_terminal_stdfd(void);
+extern int get_terminal_name(const char **path, const char **name,
+ const char **number);
+
+#define UL_TTY_KEEPCFLAGS (1 << 1)
+#define UL_TTY_UTF8 (1 << 2)
+
+static inline void reset_virtual_console(struct termios *tp, int flags)
+{
+ /* Use defaults of <sys/ttydefaults.h> for base settings */
+ tp->c_iflag |= TTYDEF_IFLAG;
+ tp->c_oflag |= TTYDEF_OFLAG;
+ tp->c_lflag |= TTYDEF_LFLAG;
+
+ if ((flags & UL_TTY_KEEPCFLAGS) == 0) {
+#ifdef CBAUD
+ tp->c_lflag &= ~CBAUD;
+#endif
+ tp->c_cflag |= (B38400 | TTYDEF_CFLAG);
+ }
+
+ /* Sane setting, allow eight bit characters, no carriage return delay
+ * the same result as `stty sane cr0 pass8'
+ */
+#ifndef IUCLC
+# define IUCLC 0
+#endif
+#ifndef NL0
+# define NL0 0
+#endif
+#ifndef CR0
+# define CR0 0
+#endif
+#ifndef BS0
+# define BS0 0
+#endif
+#ifndef VT0
+# define VT0 0
+#endif
+#ifndef FF0
+# define FF0 0
+#endif
+#ifndef OLCUC
+# define OLCUC 0
+#endif
+#ifndef OFILL
+# define OFILL 0
+#endif
+#ifndef NLDLY
+# define NLDLY 0
+#endif
+#ifndef CRDLY
+# define CRDLY 0
+#endif
+#ifndef BSDLY
+# define BSDLY 0
+#endif
+#ifndef VTDLY
+# define VTDLY 0
+#endif
+#ifndef FFDLY
+# define FFDLY 0
+#endif
+#ifndef TAB0
+# define TAB0 0
+#endif
+#ifndef TABDLY
+# define TABDLY 0
+#endif
+
+ tp->c_iflag |= (BRKINT | ICRNL | IMAXBEL);
+ tp->c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP);
+ tp->c_oflag |= (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
+ tp->c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | \
+ NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
+ tp->c_lflag |= (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE|ECHOCTL);
+ tp->c_lflag &= ~(ECHONL|ECHOPRT | NOFLSH | TOSTOP);
+
+ if ((flags & UL_TTY_KEEPCFLAGS) == 0) {
+ tp->c_cflag |= (CREAD | CS8 | HUPCL);
+ tp->c_cflag &= ~(PARODD | PARENB);
+ }
+#ifdef OFDEL
+ tp->c_oflag &= ~OFDEL;
+#endif
+#ifdef XCASE
+ tp->c_lflag &= ~XCASE;
+#endif
+#ifdef IUTF8
+ if (flags & UL_TTY_UTF8)
+ tp->c_iflag |= IUTF8; /* Set UTF-8 input flag */
+ else
+ tp->c_iflag &= ~IUTF8;
+#endif
+ /* VTIME and VMIN can overlap with VEOF and VEOL since they are
+ * only used for non-canonical mode. We just set the at the
+ * beginning, so nothing bad should happen.
+ */
+ tp->c_cc[VTIME] = 0;
+ tp->c_cc[VMIN] = 1;
+ tp->c_cc[VINTR] = CINTR;
+ tp->c_cc[VQUIT] = CQUIT;
+ tp->c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */
+ tp->c_cc[VKILL] = CKILL;
+ tp->c_cc[VEOF] = CEOF;
+#ifdef VSWTC
+ tp->c_cc[VSWTC] = _POSIX_VDISABLE;
+#elif defined(VSWTCH)
+ tp->c_cc[VSWTCH] = _POSIX_VDISABLE;
+#endif
+ tp->c_cc[VSTART] = CSTART;
+ tp->c_cc[VSTOP] = CSTOP;
+ tp->c_cc[VSUSP] = CSUSP;
+ tp->c_cc[VEOL] = _POSIX_VDISABLE;
+ tp->c_cc[VREPRINT] = CREPRINT;
+ tp->c_cc[VDISCARD] = CDISCARD;
+ tp->c_cc[VWERASE] = CWERASE;
+ tp->c_cc[VLNEXT] = CLNEXT;
+ tp->c_cc[VEOL2] = _POSIX_VDISABLE;
+}
+
+#endif /* UTIL_LINUX_TTYUTILS_H */
diff --git a/src/utils/include/widechar.h b/src/utils/include/widechar.h
new file mode 100644
index 0000000..c1f2cf2
--- /dev/null
+++ b/src/utils/include/widechar.h
@@ -0,0 +1,47 @@
+/* Declarations for wide characters */
+/* This file must be included last because the redefinition of wchar_t may
+ cause conflicts when system include files were included after it. */
+
+#ifdef HAVE_WIDECHAR
+
+# include <wchar.h>
+# include <wctype.h>
+
+#else /* !HAVE_WIDECHAR */
+
+# include <ctype.h>
+ /* Fallback for types */
+# define wchar_t char
+# define wint_t int
+# ifndef WEOF
+# define WEOF EOF
+# endif
+
+ /* Fallback for input operations */
+# define fgetwc fgetc
+# define getwc getc
+# define getwchar getchar
+# define fgetws fgets
+
+ /* Fallback for output operations */
+# define fputwc fputc
+# define putwc putc
+# define putwchar putchar
+# define fputws fputs
+
+ /* Fallback for character classification */
+# define iswgraph isgraph
+# define iswprint isprint
+# define iswspace isspace
+
+ /* Fallback for string functions */
+# define wcschr strchr
+# define wcsdup strdup
+# define wcslen strlen
+# define wcspbrk strpbrk
+
+# define wcwidth(c) (1)
+# define wmemset memset
+# define ungetwc ungetc
+
+#endif /* HAVE_WIDECHAR */
diff --git a/src/utils/include/xalloc.h b/src/utils/include/xalloc.h
new file mode 100644
index 0000000..c4124cb
--- /dev/null
+++ b/src/utils/include/xalloc.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * General memory allocation wrappers for malloc, realloc, calloc and strdup
+ */
+
+#ifndef UTIL_LINUX_XALLOC_H
+#define UTIL_LINUX_XALLOC_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "c.h"
+
+#ifndef XALLOC_EXIT_CODE
+# define XALLOC_EXIT_CODE EXIT_FAILURE
+#endif
+
+static inline
+__attribute__((__noreturn__))
+void __err_oom(const char *file, unsigned int line)
+{
+ err(XALLOC_EXIT_CODE, "%s: %u: cannot allocate memory", file, line);
+}
+
+#define err_oom() __err_oom(__FILE__, __LINE__)
+
+static inline
+__ul_alloc_size(1)
+__ul_returns_nonnull
+void *xmalloc(const size_t size)
+{
+ void *ret = malloc(size);
+
+ if (!ret && size)
+ err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+ return ret;
+}
+
+static inline
+__ul_alloc_size(2)
+__ul_returns_nonnull
+void *xrealloc(void *ptr, const size_t size)
+{
+ void *ret = realloc(ptr, size);
+
+ if (!ret && size)
+ err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+ return ret;
+}
+
+static inline
+__ul_calloc_size(1, 2)
+__ul_returns_nonnull
+void *xcalloc(const size_t nelems, const size_t size)
+{
+ void *ret = calloc(nelems, size);
+
+ if (!ret && size && nelems)
+ err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
+ return ret;
+}
+
+static inline
+__attribute__((warn_unused_result))
+__ul_returns_nonnull
+char *xstrdup(const char *str)
+{
+ char *ret;
+
+ assert(str);
+ ret = strdup(str);
+ if (!ret)
+ err(XALLOC_EXIT_CODE, "cannot duplicate string");
+ return ret;
+}
+
+static inline
+__attribute__((warn_unused_result))
+__ul_returns_nonnull
+char *xstrndup(const char *str, size_t size)
+{
+ char *ret;
+
+ assert(str);
+ ret = strndup(str, size);
+ if (!ret)
+ err(XALLOC_EXIT_CODE, "cannot duplicate string");
+ return ret;
+}
+
+
+static inline
+__attribute__((__format__(printf, 2, 3)))
+int xasprintf(char **strp, const char *fmt, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = vasprintf(&(*strp), fmt, args);
+ va_end(args);
+ if (ret < 0)
+ err(XALLOC_EXIT_CODE, "cannot allocate string");
+ return ret;
+}
+
+static inline
+__attribute__((__format__(printf, 2, 0)))
+int xvasprintf(char **strp, const char *fmt, va_list ap)
+{
+ int ret = vasprintf(&(*strp), fmt, ap);
+
+ if (ret < 0)
+ err(XALLOC_EXIT_CODE, "cannot allocate string");
+ return ret;
+}
+
+
+static inline
+__attribute__((warn_unused_result))
+char *xgethostname(void)
+{
+ char *name;
+ size_t sz = get_hostname_max() + 1;
+
+ name = xmalloc(sizeof(char) * sz);
+ if (gethostname(name, sz) != 0) {
+ free(name);
+ return NULL;
+ }
+ name[sz - 1] = '\0';
+ return name;
+}
+
+#endif
diff --git a/src/utils/lib/CMakeLists.txt b/src/utils/lib/CMakeLists.txt
new file mode 100644
index 0000000..e5fa459
--- /dev/null
+++ b/src/utils/lib/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-utils-lib)
+
+add_library(libcommon STATIC ${CMAKE_CURRENT_SOURCE_DIR}/blkdev.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/canonicalize.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/caputils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/color-names.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/colors.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/cpuset.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/crc32.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/crc32c.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/encode.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/env.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/exec_shell.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/fileutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/idcache.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/ismounted.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/langinfo.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/linux_version.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/loopdev.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mangle.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/match.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mbsalign.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/mbsedit.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/md5.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/monotonic.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pager.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/path.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/plymouth-ctrl.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/procutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pty-session.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/pwdutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/randutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/setproctitle.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/sha1.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/signames.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/strutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/strv.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/sysfs.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/timer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/timeutils.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/ttyutils.c)
diff --git a/src/utils/lib/blkdev.c b/src/utils/lib/blkdev.c
new file mode 100644
index 0000000..c22853d
--- /dev/null
+++ b/src/utils/lib/blkdev.c
@@ -0,0 +1,452 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+
+#ifdef HAVE_SYS_DISK_H
+# include <sys/disk.h>
+#endif
+
+#ifndef EBADFD
+# define EBADFD 77 /* File descriptor in bad state */
+#endif
+
+#include "blkdev.h"
+#include "c.h"
+#include "linux_version.h"
+#include "fileutils.h"
+#include "nls.h"
+
+static long
+blkdev_valid_offset (int fd, off_t offset) {
+ char ch;
+
+ if (lseek (fd, offset, 0) < 0)
+ return 0;
+ if (read (fd, &ch, 1) < 1)
+ return 0;
+ return 1;
+}
+
+int is_blkdev(int fd)
+{
+ struct stat st;
+ return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode));
+}
+
+off_t
+blkdev_find_size (int fd) {
+ uintmax_t high, low = 0;
+
+ for (high = 1024; blkdev_valid_offset (fd, high); ) {
+ if (high == UINTMAX_MAX)
+ return -1;
+
+ low = high;
+
+ if (high >= UINTMAX_MAX/2)
+ high = UINTMAX_MAX;
+ else
+ high *= 2;
+ }
+
+ while (low < high - 1)
+ {
+ uintmax_t mid = (low + high) / 2;
+
+ if (blkdev_valid_offset (fd, mid))
+ low = mid;
+ else
+ high = mid;
+ }
+ blkdev_valid_offset (fd, 0);
+ return (low + 1);
+}
+
+/* get size in bytes */
+int
+blkdev_get_size(int fd, unsigned long long *bytes)
+{
+#ifdef DKIOCGETBLOCKCOUNT
+ /* Apple Darwin */
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) {
+ *bytes <<= 9;
+ return 0;
+ }
+#endif
+
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
+ return 0;
+#endif
+
+#ifdef BLKGETSIZE
+ {
+ unsigned long size;
+
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ *bytes = ((unsigned long long)size << 9);
+ return 0;
+ }
+ }
+
+#endif /* BLKGETSIZE */
+
+#ifdef DIOCGMEDIASIZE
+ /* FreeBSD */
+ if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0)
+ return 0;
+#endif
+
+#ifdef FDGETPRM
+ {
+ struct floppy_struct this_floppy;
+
+ if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
+ *bytes = ((unsigned long long) this_floppy.size) << 9;
+ return 0;
+ }
+ }
+#endif /* FDGETPRM */
+
+#if defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO)
+ {
+ /*
+ * This code works for FreeBSD 4.11 i386, except for the full device
+ * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
+ * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
+ * above however.
+ *
+ * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
+ * character) devices, so we need to check for S_ISCHR, too.
+ */
+ int part = -1;
+ struct disklabel lab;
+ struct partition *pp;
+ struct stat st;
+
+ if ((fstat(fd, &st) >= 0) &&
+ (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
+ part = st.st_rdev & 7;
+
+ if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+ pp = &lab.d_partitions[part];
+ if (pp->p_size) {
+ *bytes = pp->p_size << 9;
+ return 0;
+ }
+ }
+ }
+#endif /* defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) */
+
+ {
+ struct stat st;
+
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
+ *bytes = st.st_size;
+ return 0;
+ }
+ if (!S_ISBLK(st.st_mode))
+ return -1;
+ }
+
+ *bytes = blkdev_find_size(fd);
+ return 0;
+}
+
+/* get 512-byte sector count */
+int
+blkdev_get_sectors(int fd, unsigned long long *sectors)
+{
+ unsigned long long bytes;
+
+ if (blkdev_get_size(fd, &bytes) == 0) {
+ *sectors = (bytes >> 9);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Get logical sector size.
+ *
+ * This is the smallest unit the storage device can
+ * address. It is typically 512 bytes.
+ */
+#ifdef BLKSSZGET
+int blkdev_get_sector_size(int fd, int *sector_size)
+{
+ if (ioctl(fd, BLKSSZGET, sector_size) >= 0)
+ return 0;
+ return -1;
+}
+#else
+int blkdev_get_sector_size(int fd __attribute__((__unused__)), int *sector_size)
+{
+ *sector_size = DEFAULT_SECTOR_SIZE;
+ return 0;
+}
+#endif
+
+/*
+ * Get physical block device size. The BLKPBSZGET is supported since Linux
+ * 2.6.32. For old kernels is probably the best to assume that physical sector
+ * size is the same as logical sector size.
+ *
+ * Example:
+ *
+ * rc = blkdev_get_physector_size(fd, &physec);
+ * if (rc || physec == 0) {
+ * rc = blkdev_get_sector_size(fd, &physec);
+ * if (rc)
+ * physec = DEFAULT_SECTOR_SIZE;
+ * }
+ */
+#ifdef BLKPBSZGET
+int blkdev_get_physector_size(int fd, int *sector_size)
+{
+ if (ioctl(fd, BLKPBSZGET, &sector_size) >= 0)
+ return 0;
+ return -1;
+}
+#else
+int blkdev_get_physector_size(int fd __attribute__((__unused__)), int *sector_size)
+{
+ *sector_size = DEFAULT_SECTOR_SIZE;
+ return 0;
+}
+#endif
+
+/*
+ * Return the alignment status of a device
+ */
+#ifdef BLKALIGNOFF
+int blkdev_is_misaligned(int fd)
+{
+ int aligned;
+
+ if (ioctl(fd, BLKALIGNOFF, &aligned) < 0)
+ return 0; /* probably kernel < 2.6.32 */
+ /*
+ * Note that kernel returns -1 as alignment offset if no compatible
+ * sizes and alignments exist for stacked devices
+ */
+ return aligned != 0 ? 1 : 0;
+}
+#else
+int blkdev_is_misaligned(int fd __attribute__((__unused__)))
+{
+ return 0;
+}
+#endif
+
+int open_blkdev_or_file(const struct stat *st, const char *name, const int oflag)
+{
+ int fd;
+
+ if (S_ISBLK(st->st_mode)) {
+ fd = open(name, oflag | O_EXCL);
+ } else
+ fd = open(name, oflag);
+ if (-1 < fd && !is_same_inode(fd, st)) {
+ close(fd);
+ errno = EBADFD;
+ return -1;
+ }
+ if (-1 < fd && S_ISBLK(st->st_mode) && blkdev_is_misaligned(fd))
+ warnx(_("warning: %s is misaligned"), name);
+ return fd;
+}
+
+#ifdef CDROM_GET_CAPABILITY
+int blkdev_is_cdrom(int fd)
+{
+ int ret;
+
+ if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0)
+ return 0;
+
+ return ret;
+}
+#else
+int blkdev_is_cdrom(int fd __attribute__((__unused__)))
+{
+ return 0;
+}
+#endif
+
+/*
+ * Get kernel's interpretation of the device's geometry.
+ *
+ * Returns the heads and sectors - but not cylinders
+ * as it's truncated for disks with more than 65535 tracks.
+ *
+ * Note that this is deprecated in favor of LBA addressing.
+ */
+#ifdef HDIO_GETGEO
+int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s)
+{
+ struct hd_geometry geometry;
+
+ if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
+ *h = geometry.heads;
+ *s = geometry.sectors;
+ return 0;
+ }
+#else
+int blkdev_get_geometry(int fd __attribute__((__unused__)),
+ unsigned int *h, unsigned int *s)
+{
+ *h = 0;
+ *s = 0;
+#endif
+ return -1;
+}
+
+/*
+ * Convert scsi type to human readable string.
+ */
+const char *blkdev_scsi_type_to_name(int type)
+{
+ switch (type) {
+ case SCSI_TYPE_DISK:
+ return "disk";
+ case SCSI_TYPE_TAPE:
+ return "tape";
+ case SCSI_TYPE_PRINTER:
+ return "printer";
+ case SCSI_TYPE_PROCESSOR:
+ return "processor";
+ case SCSI_TYPE_WORM:
+ return "worm";
+ case SCSI_TYPE_ROM:
+ return "rom";
+ case SCSI_TYPE_SCANNER:
+ return "scanner";
+ case SCSI_TYPE_MOD:
+ return "mo-disk";
+ case SCSI_TYPE_MEDIUM_CHANGER:
+ return "changer";
+ case SCSI_TYPE_COMM:
+ return "comm";
+ case SCSI_TYPE_RAID:
+ return "raid";
+ case SCSI_TYPE_ENCLOSURE:
+ return "enclosure";
+ case SCSI_TYPE_RBC:
+ return "rbc";
+ case SCSI_TYPE_OSD:
+ return "osd";
+ case SCSI_TYPE_NO_LUN:
+ return "no-lun";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/* return 0 on success */
+int blkdev_lock(int fd, const char *devname, const char *lockmode)
+{
+ int oper, rc, msg = 0;
+
+ if (!lockmode)
+ lockmode = getenv("LOCK_BLOCK_DEVICE");
+ if (!lockmode)
+ return 0;
+
+ if (strcasecmp(lockmode, "yes") == 0 ||
+ strcmp(lockmode, "1") == 0)
+ oper = LOCK_EX;
+
+ else if (strcasecmp(lockmode, "nonblock") == 0)
+ oper = LOCK_EX | LOCK_NB;
+
+ else if (strcasecmp(lockmode, "no") == 0 ||
+ strcmp(lockmode, "0") == 0)
+ return 0;
+ else {
+ warnx(_("unsupported lock mode: %s"), lockmode);
+ return -EINVAL;
+ }
+
+ if (!(oper & LOCK_NB)) {
+ /* Try non-block first to provide message */
+ rc = flock(fd, oper | LOCK_NB);
+ if (rc == 0)
+ return 0;
+ if (rc != 0 && errno == EWOULDBLOCK) {
+ fprintf(stderr, _("%s: %s: device already locked, waiting to get lock ... "),
+ program_invocation_short_name, devname);
+ msg = 1;
+ }
+ }
+ rc = flock(fd, oper);
+ if (rc != 0) {
+ switch (errno) {
+ case EWOULDBLOCK: /* LOCK_NB */
+ warnx(_("%s: device already locked"), devname);
+ break;
+ default:
+ warn(_("%s: failed to get lock"), devname);
+ }
+ } else if (msg)
+ fprintf(stderr, _("OK\n"));
+ return rc;
+}
+
+
+#ifdef TEST_PROGRAM_BLKDEV
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+int
+main(int argc, char **argv)
+{
+ unsigned long long bytes;
+ unsigned long long sectors;
+ int sector_size, phy_sector_size;
+ int fd;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s device\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((fd = open(argv[1], O_RDONLY|O_CLOEXEC)) < 0)
+ err(EXIT_FAILURE, "open %s failed", argv[1]);
+
+ if (blkdev_get_size(fd, &bytes) < 0)
+ err(EXIT_FAILURE, "blkdev_get_size() failed");
+ if (blkdev_get_sectors(fd, &sectors) < 0)
+ err(EXIT_FAILURE, "blkdev_get_sectors() failed");
+ if (blkdev_get_sector_size(fd, &sector_size) < 0)
+ err(EXIT_FAILURE, "blkdev_get_sector_size() failed");
+ if (blkdev_get_physector_size(fd, &phy_sector_size) < 0)
+ err(EXIT_FAILURE, "blkdev_get_physector_size() failed");
+
+ printf(" bytes: %llu\n", bytes);
+ printf(" sectors: %llu\n", sectors);
+ printf(" sector size: %d\n", sector_size);
+ printf("phy-sector size: %d\n", phy_sector_size);
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_BLKDEV */
diff --git a/src/utils/lib/canonicalize.c b/src/utils/lib/canonicalize.c
new file mode 100644
index 0000000..e101c5b
--- /dev/null
+++ b/src/utils/lib/canonicalize.c
@@ -0,0 +1,250 @@
+/*
+ * canonicalize.c -- canonicalize pathname by removing symlinks
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "canonicalize.h"
+#include "pathnames.h"
+#include "all-io.h"
+
+/*
+ * Converts private "dm-N" names to "/dev/mapper/<name>"
+ *
+ * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
+ * provides the real DM device names in /sys/block/<ptname>/dm/name
+ */
+char *__canonicalize_dm_name(const char *prefix, const char *ptname)
+{
+ FILE *f;
+ size_t sz;
+ char path[256], name[sizeof(path) - sizeof(_PATH_DEV_MAPPER)], *res = NULL;
+
+ if (!ptname || !*ptname)
+ return NULL;
+
+ if (!prefix)
+ prefix = "";
+
+ snprintf(path, sizeof(path), "%s/sys/block/%s/dm/name", prefix, ptname);
+ if (!(f = fopen(path, "r" UL_CLOEXECSTR)))
+ return NULL;
+
+ /* read "<name>\n" from sysfs */
+ if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
+ name[sz - 1] = '\0';
+ snprintf(path, sizeof(path), _PATH_DEV_MAPPER "/%s", name);
+
+ if ((prefix && *prefix) || access(path, F_OK) == 0)
+ res = strdup(path);
+ }
+ fclose(f);
+ return res;
+}
+
+char *canonicalize_dm_name(const char *ptname)
+{
+ return __canonicalize_dm_name(NULL, ptname);
+}
+
+static int is_dm_devname(char *canonical, char **name)
+{
+ struct stat sb;
+ char *p = strrchr(canonical, '/');
+
+ *name = NULL;
+
+ if (!p
+ || strncmp(p, "/dm-", 4) != 0
+ || !isdigit(*(p + 4))
+ || stat(canonical, &sb) != 0
+ || !S_ISBLK(sb.st_mode))
+ return 0;
+
+ *name = p + 1;
+ return 1;
+}
+
+/*
+ * This function does not canonicalize the path! It just prepends CWD before a
+ * relative path. If the path is no relative than returns NULL. The path does
+ * not have to exist.
+ */
+char *absolute_path(const char *path)
+{
+ char cwd[PATH_MAX], *res, *p;
+ size_t psz, csz;
+
+ if (!is_relative_path(path)) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (!getcwd(cwd, sizeof(cwd)))
+ return NULL;
+
+ /* simple clean up */
+ if (startswith(path, "./"))
+ path += 2;
+ else if (strcmp(path, ".") == 0)
+ path = NULL;
+
+ if (!path || !*path)
+ return strdup(cwd);
+
+ csz = strlen(cwd);
+ psz = strlen(path);
+
+ p = res = malloc(csz + 1 + psz + 1);
+ if (!res)
+ return NULL;
+
+ memcpy(p, cwd, csz);
+ p += csz;
+ *p++ = '/';
+ memcpy(p, path, psz + 1);
+
+ return res;
+}
+
+char *canonicalize_path(const char *path)
+{
+ char *canonical, *dmname;
+
+ if (!path || !*path)
+ return NULL;
+
+ canonical = realpath(path, NULL);
+ if (!canonical)
+ return strdup(path);
+
+ if (is_dm_devname(canonical, &dmname)) {
+ char *dm = canonicalize_dm_name(dmname);
+ if (dm) {
+ free(canonical);
+ return dm;
+ }
+ }
+
+ return canonical;
+}
+
+char *canonicalize_path_restricted(const char *path)
+{
+ char *canonical = NULL;
+ int errsv = 0;
+ int pipes[2];
+ ssize_t len;
+ pid_t pid;
+
+ if (!path || !*path)
+ return NULL;
+
+ if (pipe(pipes) != 0)
+ return NULL;
+
+ /*
+ * To accurately assume identity of getuid() we must use setuid()
+ * but if we do that, we lose ability to reassume euid of 0, so
+ * we fork to do the check to keep euid intact.
+ */
+ pid = fork();
+ switch (pid) {
+ case -1:
+ close(pipes[0]);
+ close(pipes[1]);
+ return NULL; /* fork error */
+ case 0:
+ close(pipes[0]); /* close unused end */
+ pipes[0] = -1;
+ errno = 0;
+
+ /* drop permissions */
+ if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
+ canonical = NULL; /* failed */
+ else {
+ char *dmname = NULL;
+
+ canonical = realpath(path, NULL);
+ if (canonical && is_dm_devname(canonical, &dmname)) {
+ char *dm = canonicalize_dm_name(dmname);
+ if (dm) {
+ free(canonical);
+ canonical = dm;
+ }
+ }
+ }
+
+ len = canonical ? (ssize_t) strlen(canonical) :
+ errno ? -errno : -EINVAL;
+
+ /* send length or errno */
+ write_all(pipes[1], (char *) &len, sizeof(len));
+ if (canonical)
+ write_all(pipes[1], canonical, len);
+ exit(0);
+ default:
+ break;
+ }
+
+ close(pipes[1]); /* close unused end */
+ pipes[1] = -1;
+
+ /* read size or -errno */
+ if (read_all(pipes[0], (char *) &len, sizeof(len)) != sizeof(len))
+ goto done;
+ if (len < 0) {
+ errsv = -len;
+ goto done;
+ }
+
+ canonical = malloc(len + 1);
+ if (!canonical) {
+ errsv = ENOMEM;
+ goto done;
+ }
+ /* read path */
+ if (read_all(pipes[0], canonical, len) != len) {
+ errsv = errno;
+ goto done;
+ }
+ canonical[len] = '\0';
+done:
+ if (errsv) {
+ free(canonical);
+ canonical = NULL;
+ }
+ close(pipes[0]);
+
+ /* We make a best effort to reap child */
+ waitpid(pid, NULL, 0);
+
+ errno = errsv;
+ return canonical;
+}
+
+
+#ifdef TEST_PROGRAM_CANONICALIZE
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <device>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stdout, "orig: %s\n", argv[1]);
+ fprintf(stdout, "real: %s\n", canonicalize_path(argv[1]));
+ exit(EXIT_SUCCESS);
+}
+#endif
diff --git a/src/utils/lib/caputils.c b/src/utils/lib/caputils.c
new file mode 100644
index 0000000..17e9c01
--- /dev/null
+++ b/src/utils/lib/caputils.c
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+
+#include "caputils.h"
+#include "pathnames.h"
+
+int cap_last_cap(void)
+{
+ /* CAP_LAST_CAP is untrustworthy. */
+ static int ret = -1;
+ int matched;
+ FILE *f;
+
+ if (ret != -1)
+ return ret;
+
+ f = fopen(_PATH_PROC_CAPLASTCAP, "r");
+ if (!f) {
+ ret = CAP_LAST_CAP; /* guess */
+ return ret;
+ }
+
+ matched = fscanf(f, "%d", &ret);
+ fclose(f);
+
+ if (matched != 1)
+ ret = CAP_LAST_CAP; /* guess */
+
+ return ret;
+}
diff --git a/src/utils/lib/color-names.c b/src/utils/lib/color-names.c
new file mode 100644
index 0000000..9b1505e
--- /dev/null
+++ b/src/utils/lib/color-names.c
@@ -0,0 +1,64 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include "c.h"
+#include "color-names.h"
+
+struct ul_color_name {
+ const char *name;
+ const char *seq;
+};
+
+/*
+ * qsort/bsearch buddy
+ */
+static int cmp_color_name(const void *a0, const void *b0)
+{
+ const struct ul_color_name
+ *a = (const struct ul_color_name *) a0,
+ *b = (const struct ul_color_name *) b0;
+ return strcmp(a->name, b->name);
+}
+
+/*
+ * Maintains human readable color names
+ */
+const char *color_sequence_from_colorname(const char *str)
+{
+ static const struct ul_color_name basic_schemes[] = {
+ { "black", UL_COLOR_BLACK },
+ { "blink", UL_COLOR_BLINK },
+ { "blue", UL_COLOR_BLUE },
+ { "bold", UL_COLOR_BOLD },
+ { "brown", UL_COLOR_BROWN },
+ { "cyan", UL_COLOR_CYAN },
+ { "darkgray", UL_COLOR_DARK_GRAY },
+ { "gray", UL_COLOR_GRAY },
+ { "green", UL_COLOR_GREEN },
+ { "halfbright", UL_COLOR_HALFBRIGHT },
+ { "lightblue", UL_COLOR_BOLD_BLUE },
+ { "lightcyan", UL_COLOR_BOLD_CYAN },
+ { "lightgray,", UL_COLOR_GRAY },
+ { "lightgreen", UL_COLOR_BOLD_GREEN },
+ { "lightmagenta", UL_COLOR_BOLD_MAGENTA },
+ { "lightred", UL_COLOR_BOLD_RED },
+ { "magenta", UL_COLOR_MAGENTA },
+ { "red", UL_COLOR_RED },
+ { "reset", UL_COLOR_RESET, },
+ { "reverse", UL_COLOR_REVERSE },
+ { "yellow", UL_COLOR_BOLD_YELLOW },
+ { "white", UL_COLOR_WHITE }
+ };
+ struct ul_color_name key = { .name = str }, *res;
+
+ if (!str)
+ return NULL;
+
+ res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes),
+ sizeof(struct ul_color_name),
+ cmp_color_name);
+ return res ? res->seq : NULL;
+}
diff --git a/src/utils/lib/colors.c b/src/utils/lib/colors.c
new file mode 100644
index 0000000..e317519
--- /dev/null
+++ b/src/utils/lib/colors.c
@@ -0,0 +1,907 @@
+/*
+ * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW)
+# if defined(HAVE_NCURSESW_NCURSES_H)
+# include <ncursesw/ncurses.h>
+# elif defined(HAVE_NCURSES_NCURSES_H)
+# include <ncurses/ncurses.h>
+# elif defined(HAVE_NCURSES_H)
+# include <ncurses.h>
+# endif
+# if defined(HAVE_NCURSESW_TERM_H)
+# include <ncursesw/term.h>
+# elif defined(HAVE_NCURSES_TERM_H)
+# include <ncurses/term.h>
+# elif defined(HAVE_TERM_H)
+# include <term.h>
+# endif
+#endif
+
+#include "c.h"
+#include "colors.h"
+#include "pathnames.h"
+#include "strutils.h"
+
+#include "debug.h"
+
+/*
+ * Default behavior, may be overridden by terminal-colors.d/{enable,disable}.
+ */
+#ifdef USE_COLORS_BY_DEFAULT
+# define UL_COLORMODE_DEFAULT UL_COLORMODE_AUTO /* check isatty() */
+#else
+# define UL_COLORMODE_DEFAULT UL_COLORMODE_NEVER /* no colors by default */
+#endif
+
+/*
+ * terminal-colors.d debug stuff
+ */
+static UL_DEBUG_DEFINE_MASK(termcolors);
+UL_DEBUG_DEFINE_MASKNAMES(termcolors) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define TERMCOLORS_DEBUG_INIT (1 << 1)
+#define TERMCOLORS_DEBUG_CONF (1 << 2)
+#define TERMCOLORS_DEBUG_SCHEME (1 << 3)
+#define TERMCOLORS_DEBUG_ALL 0xFFFF
+
+#define DBG(m, x) __UL_DBG(termcolors, TERMCOLORS_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(termcolors, TERMCOLORS_DEBUG_, m, x)
+
+/*
+ * terminal-colors.d file types
+ */
+enum {
+ UL_COLORFILE_DISABLE, /* .disable */
+ UL_COLORFILE_ENABLE, /* .enable */
+ UL_COLORFILE_SCHEME, /* .scheme */
+
+ __UL_COLORFILE_COUNT
+};
+
+struct ul_color_scheme {
+ char *name;
+ char *seq;
+};
+
+/*
+ * Global colors control struct
+ *
+ * The terminal-colors.d/ evaluation is based on "scores":
+ *
+ * filename score
+ * ---------------------------------------
+ * type 1
+ * @termname.type 10 + 1
+ * utilname.type 20 + 1
+ * utilname@termname.type 20 + 10 + 1
+ *
+ * the match with higher score wins. The score is per type.
+ */
+struct ul_color_ctl {
+ const char *utilname; /* util name */
+ const char *termname; /* terminal name ($TERM) */
+
+ char *sfile; /* path to scheme */
+
+ struct ul_color_scheme *schemes; /* array with color schemes */
+ size_t nschemes; /* number of the items */
+ size_t schemes_sz; /* number of the allocated items */
+
+ int mode; /* UL_COLORMODE_* */
+ unsigned int has_colors : 1, /* based on mode and scores[] */
+ disabled : 1, /* disable colors */
+ cs_configured : 1, /* color schemes read */
+ configured : 1; /* terminal-colors.d parsed */
+
+ int scores[__UL_COLORFILE_COUNT]; /* the best match */
+};
+
+/*
+ * Control struct, globally shared.
+ */
+static struct ul_color_ctl ul_colors;
+
+static void colors_free_schemes(struct ul_color_ctl *cc);
+static int colors_read_schemes(struct ul_color_ctl *cc);
+
+/*
+ * qsort/bsearch buddy
+ */
+static int cmp_scheme_name(const void *a0, const void *b0)
+{
+ const struct ul_color_scheme *a = (const struct ul_color_scheme *) a0,
+ *b = (const struct ul_color_scheme *) b0;
+ return strcmp(a->name, b->name);
+}
+
+/*
+ * Resets control struct (note that we don't allocate the struct)
+ */
+static void colors_reset(struct ul_color_ctl *cc)
+{
+ if (!cc)
+ return;
+
+ colors_free_schemes(cc);
+
+ free(cc->sfile);
+
+ cc->sfile = NULL;
+ cc->utilname = NULL;
+ cc->termname = NULL;
+ cc->mode = UL_COLORMODE_UNDEF;
+
+ memset(cc->scores, 0, sizeof(cc->scores));
+}
+
+static void colors_debug(struct ul_color_ctl *cc)
+{
+ size_t i;
+
+ if (!cc)
+ return;
+
+ printf("Colors:\n");
+ printf("\tutilname = '%s'\n", cc->utilname);
+ printf("\ttermname = '%s'\n", cc->termname);
+ printf("\tscheme file = '%s'\n", cc->sfile);
+ printf("\tmode = %s\n",
+ cc->mode == UL_COLORMODE_UNDEF ? "undefined" :
+ cc->mode == UL_COLORMODE_AUTO ? "auto" :
+ cc->mode == UL_COLORMODE_NEVER ? "never" :
+ cc->mode == UL_COLORMODE_ALWAYS ? "always" : "???");
+ printf("\thas_colors = %d\n", cc->has_colors);
+ printf("\tdisabled = %d\n", cc->disabled);
+ printf("\tconfigured = %d\n", cc->configured);
+ printf("\tcs configured = %d\n", cc->cs_configured);
+
+ fputc('\n', stdout);
+
+ for (i = 0; i < ARRAY_SIZE(cc->scores); i++)
+ printf("\tscore %s = %d\n",
+ i == UL_COLORFILE_DISABLE ? "disable" :
+ i == UL_COLORFILE_ENABLE ? "enable" :
+ i == UL_COLORFILE_SCHEME ? "scheme" : "???",
+ cc->scores[i]);
+
+ fputc('\n', stdout);
+
+ for (i = 0; i < cc->nschemes; i++) {
+ printf("\tscheme #%02zu ", i);
+ color_scheme_enable(cc->schemes[i].name, NULL);
+ fputs(cc->schemes[i].name, stdout);
+ color_disable();
+ fputc('\n', stdout);
+ }
+ fputc('\n', stdout);
+}
+
+/*
+ * Parses [[<utilname>][@<termname>].]<type>
+ */
+static int filename_to_tokens(const char *str,
+ const char **name, size_t *namesz,
+ const char **term, size_t *termsz,
+ int *filetype)
+{
+ const char *type_start, *term_start, *p;
+
+ if (!str || !*str || *str == '.' || strlen(str) > PATH_MAX)
+ return -EINVAL;
+
+ /* parse .type */
+ p = strrchr(str, '.');
+ type_start = p ? p + 1 : str;
+
+ if (strcmp(type_start, "disable") == 0)
+ *filetype = UL_COLORFILE_DISABLE;
+ else if (strcmp(type_start, "enable") == 0)
+ *filetype = UL_COLORFILE_ENABLE;
+ else if (strcmp(type_start, "scheme") == 0)
+ *filetype = UL_COLORFILE_SCHEME;
+ else {
+ DBG(CONF, ul_debug("unknown type '%s'", type_start));
+ return 1; /* unknown type */
+ }
+
+ if (type_start == str)
+ return 0; /* "type" only */
+
+ /* parse @termname */
+ p = strchr(str, '@');
+ term_start = p ? p + 1 : NULL;
+ if (term_start) {
+ *term = term_start;
+ *termsz = type_start - term_start - 1;
+ if (term_start - 1 == str)
+ return 0; /* "@termname.type" */
+ }
+
+ /* parse utilname */
+ p = term_start ? term_start : type_start;
+ *name = str;
+ *namesz = p - str - 1;
+
+ return 0;
+}
+
+/*
+ * Scans @dirname and select the best matches for UL_COLORFILE_* types.
+ * The result is stored to cc->scores. The path to the best "scheme"
+ * file is stored to cc->scheme.
+ */
+static int colors_readdir(struct ul_color_ctl *cc, const char *dirname)
+{
+ DIR *dir;
+ int rc = 0;
+ struct dirent *d;
+ char sfile[PATH_MAX] = { '\0' };
+ size_t namesz, termsz;
+
+ if (!dirname || !cc || !cc->utilname || !*cc->utilname)
+ return -EINVAL;
+
+ DBG(CONF, ul_debug("reading dir: '%s'", dirname));
+
+ dir = opendir(dirname);
+ if (!dir)
+ return -errno;
+
+ namesz = strlen(cc->utilname);
+ termsz = cc->termname ? strlen(cc->termname) : 0;
+
+ while ((d = readdir(dir))) {
+ int type, score = 1;
+ const char *tk_name = NULL, *tk_term = NULL;
+ size_t tk_namesz = 0, tk_termsz = 0;
+
+ if (*d->d_name == '.')
+ continue;
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK &&
+ d->d_type != DT_REG)
+ continue;
+#endif
+ if (filename_to_tokens(d->d_name,
+ &tk_name, &tk_namesz,
+ &tk_term, &tk_termsz, &type) != 0)
+ continue;
+
+ /* count theoretical score before we check names to avoid
+ * unnecessary strcmp() */
+ if (tk_name)
+ score += 20;
+ if (tk_term)
+ score += 10;
+
+ DBG(CONF, ul_debug("item '%s': score=%d "
+ "[cur: %d, name(%zu): %s, term(%zu): %s]",
+ d->d_name, score, cc->scores[type],
+ tk_namesz, tk_name,
+ tk_termsz, tk_term));
+
+
+ if (score < cc->scores[type])
+ continue;
+
+ /* filter out by names */
+ if (tk_namesz && (tk_namesz != namesz ||
+ strncmp(tk_name, cc->utilname, namesz) != 0))
+ continue;
+
+ if (tk_termsz && (termsz == 0 || tk_termsz != termsz ||
+ strncmp(tk_term, cc->termname, termsz) != 0))
+ continue;
+
+ DBG(CONF, ul_debug("setting '%s' from %d -to-> %d",
+ type == UL_COLORFILE_SCHEME ? "scheme" :
+ type == UL_COLORFILE_DISABLE ? "disable" :
+ type == UL_COLORFILE_ENABLE ? "enable" : "???",
+ cc->scores[type], score));
+ cc->scores[type] = score;
+ if (type == UL_COLORFILE_SCHEME)
+ strncpy(sfile, d->d_name, sizeof(sfile));
+ }
+
+ if (*sfile) {
+ sfile[sizeof(sfile) - 1] = '\0';
+ if (asprintf(&cc->sfile, "%s/%s", dirname, sfile) <= 0)
+ rc = -ENOMEM;
+ }
+
+ closedir(dir);
+ return rc;
+}
+
+/* atexit() wrapper */
+static void colors_deinit(void)
+{
+ colors_reset(&ul_colors);
+}
+
+/*
+ * Returns path to $XDG_CONFIG_HOME/terminal-colors.d
+ */
+static char *colors_get_homedir(char *buf, size_t bufsz)
+{
+ char *p = getenv("XDG_CONFIG_HOME");
+
+ if (p) {
+ snprintf(buf, bufsz, "%s/" _PATH_TERMCOLORS_DIRNAME, p);
+ return buf;
+ }
+
+ p = getenv("HOME");
+ if (p) {
+ snprintf(buf, bufsz, "%s/.config/" _PATH_TERMCOLORS_DIRNAME, p);
+ return buf;
+ }
+
+ return NULL;
+}
+
+/* canonicalize sequence */
+static int cn_sequence(const char *str, char **seq)
+{
+ char *in, *out;
+ int len;
+
+ if (!str)
+ return -EINVAL;
+
+ *seq = NULL;
+
+ /* convert logical names like "red" to the real sequence */
+ if (*str != '\\' && isalpha(*str)) {
+ const char *s = color_sequence_from_colorname(str);
+ *seq = strdup(s ? s : str);
+
+ return *seq ? 0 : -ENOMEM;
+ }
+
+ /* convert xx;yy sequences to "\033[xx;yy" */
+ if ((len = asprintf(seq, "\033[%sm", str)) < 1)
+ return -ENOMEM;
+
+ for (in = *seq, out = *seq; in && *in; in++) {
+ if (*in != '\\') {
+ *out++ = *in;
+ continue;
+ }
+ switch(*(in + 1)) {
+ case 'a':
+ *out++ = '\a'; /* Bell */
+ break;
+ case 'b':
+ *out++ = '\b'; /* Backspace */
+ break;
+ case 'e':
+ *out++ = '\033'; /* Escape */
+ break;
+ case 'f':
+ *out++ = '\f'; /* Form Feed */
+ break;
+ case 'n':
+ *out++ = '\n'; /* Newline */
+ break;
+ case 'r':
+ *out++ = '\r'; /* Carriage Return */
+ break;
+ case 't':
+ *out++ = '\t'; /* Tab */
+ break;
+ case 'v':
+ *out++ = '\v'; /* Vertical Tab */
+ break;
+ case '\\':
+ *out++ = '\\'; /* Backslash */
+ break;
+ case '_':
+ *out++ = ' '; /* Space */
+ break;
+ case '#':
+ *out++ = '#'; /* Hash mark */
+ break;
+ case '?':
+ *out++ = '?'; /* Question mark */
+ break;
+ default:
+ *out++ = *in;
+ *out++ = *(in + 1);
+ break;
+ }
+ in++;
+ }
+
+ if (out) {
+ assert ((out - *seq) <= len);
+ *out = '\0';
+ }
+
+ return 0;
+}
+
+
+/*
+ * Adds one color sequence to array with color scheme.
+ * When returning success (0) this function takes ownership of
+ * @seq and @name, which have to be allocated strings.
+ */
+static int colors_add_scheme(struct ul_color_ctl *cc,
+ char *name,
+ char *seq0)
+{
+ struct ul_color_scheme *cs = NULL;
+ char *seq = NULL;
+ int rc;
+
+ if (!cc || !name || !*name || !seq0 || !*seq0)
+ return -EINVAL;
+
+ DBG(SCHEME, ul_debug("add '%s'", name));
+
+ rc = cn_sequence(seq0, &seq);
+ if (rc)
+ return rc;
+
+ rc = -ENOMEM;
+
+ /* convert logical name (e.g. "red") to real ESC code */
+ if (isalpha(*seq)) {
+ const char *s = color_sequence_from_colorname(seq);
+ char *p;
+
+ if (!s) {
+ DBG(SCHEME, ul_debug("unknown logical name: %s", seq));
+ rc = -EINVAL;
+ goto err;
+ }
+
+ p = strdup(s);
+ if (!p)
+ goto err;
+ free(seq);
+ seq = p;
+ }
+
+ /* enlarge the array */
+ if (cc->nschemes == cc->schemes_sz) {
+ void *tmp = realloc(cc->schemes, (cc->nschemes + 10)
+ * sizeof(struct ul_color_scheme));
+ if (!tmp)
+ goto err;
+ cc->schemes = tmp;
+ cc->schemes_sz = cc->nschemes + 10;
+ }
+
+ /* add a new item */
+ cs = &cc->schemes[cc->nschemes];
+ cs->seq = seq;
+ cs->name = strdup(name);
+ if (!cs->name)
+ goto err;
+
+ cc->nschemes++;
+ return 0;
+err:
+ if (cs) {
+ free(cs->seq);
+ free(cs->name);
+ cs->seq = cs->name = NULL;
+ } else
+ free(seq);
+ return rc;
+}
+
+/*
+ * Deallocates all regards to color schemes
+ */
+static void colors_free_schemes(struct ul_color_ctl *cc)
+{
+ size_t i;
+
+ DBG(SCHEME, ul_debug("free scheme"));
+
+ for (i = 0; i < cc->nschemes; i++) {
+ free(cc->schemes[i].name);
+ free(cc->schemes[i].seq);
+ }
+
+ free(cc->schemes);
+ cc->schemes = NULL;
+ cc->nschemes = 0;
+ cc->schemes_sz = 0;
+}
+
+/*
+ * The scheme configuration has to be sorted for bsearch
+ */
+static void colors_sort_schemes(struct ul_color_ctl *cc)
+{
+ if (!cc->nschemes)
+ return;
+
+ DBG(SCHEME, ul_debug("sort scheme"));
+
+ qsort(cc->schemes, cc->nschemes,
+ sizeof(struct ul_color_scheme), cmp_scheme_name);
+}
+
+/*
+ * Returns just one color scheme
+ */
+static struct ul_color_scheme *colors_get_scheme(struct ul_color_ctl *cc,
+ const char *name)
+{
+ struct ul_color_scheme key = { .name = (char *) name}, *res;
+
+ if (!cc || !name || !*name)
+ return NULL;
+
+ if (!cc->cs_configured) {
+ int rc = colors_read_schemes(cc);
+ if (rc)
+ return NULL;
+ }
+ if (!cc->nschemes)
+ return NULL;
+
+ DBG(SCHEME, ul_debug("search '%s'", name));
+
+ res = bsearch(&key, cc->schemes, cc->nschemes,
+ sizeof(struct ul_color_scheme),
+ cmp_scheme_name);
+
+ return res && res->seq ? res : NULL;
+}
+
+/*
+ * Parses filenames in terminal-colors.d
+ */
+static int colors_read_configuration(struct ul_color_ctl *cc)
+{
+ int rc = -ENOENT;
+ char *dirname, buf[PATH_MAX];
+
+ cc->termname = getenv("TERM");
+
+ dirname = colors_get_homedir(buf, sizeof(buf));
+ if (dirname)
+ rc = colors_readdir(cc, dirname); /* ~/.config */
+ if (rc == -EPERM || rc == -EACCES || rc == -ENOENT)
+ rc = colors_readdir(cc, _PATH_TERMCOLORS_DIR); /* /etc */
+
+ cc->configured = 1;
+ return rc;
+}
+
+/*
+ * Reads terminal-colors.d/ scheme file into array schemes
+ */
+static int colors_read_schemes(struct ul_color_ctl *cc)
+{
+ int rc = 0;
+ FILE *f = NULL;
+ char buf[BUFSIZ],
+ cn[129], seq[129];
+
+ if (!cc->configured)
+ rc = colors_read_configuration(cc);
+
+ cc->cs_configured = 1;
+
+ if (rc || !cc->sfile)
+ goto done;
+
+ DBG(SCHEME, ul_debug("reading file '%s'", cc->sfile));
+
+ f = fopen(cc->sfile, "r");
+ if (!f) {
+ rc = -errno;
+ goto done;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ char *p = strchr(buf, '\n');
+
+ if (!p) {
+ if (feof(f))
+ p = strchr(buf, '\0');
+ else {
+ rc = -errno;
+ goto done;
+ }
+ }
+ *p = '\0';
+ p = (char *) skip_blank(buf);
+ if (*p == '\0' || *p == '#')
+ continue;
+
+ rc = sscanf(p, "%128[^ ] %128[^\n ]", cn, seq);
+ if (rc == 2 && *cn && *seq) {
+ rc = colors_add_scheme(cc, cn, seq); /* set rc=0 on success */
+ if (rc)
+ goto done;
+ }
+ }
+ rc = 0;
+
+done:
+ if (f)
+ fclose(f);
+ colors_sort_schemes(cc);
+
+ return rc;
+}
+
+
+static void termcolors_init_debug(void)
+{
+ __UL_INIT_DEBUG_FROM_ENV(termcolors, TERMCOLORS_DEBUG_, 0, TERMINAL_COLORS_DEBUG);
+}
+
+static int colors_terminal_is_ready(void)
+{
+ int ncolors = -1;
+
+#if defined(HAVE_LIBNCURSES) || defined(HAVE_LIBNCURSESW)
+ {
+ int ret;
+
+ if (setupterm(NULL, STDOUT_FILENO, &ret) == 0 && ret == 1)
+ ncolors = tigetnum("colors");
+ }
+#endif
+ if (1 < ncolors) {
+ DBG(CONF, ul_debug("terminal is ready (supports %d colors)", ncolors));
+ return 1;
+ }
+
+ DBG(CONF, ul_debug("terminal is NOT ready (no colors)"));
+ return 0;
+}
+
+/**
+ * colors_init:
+ * @mode: UL_COLORMODE_*
+ * @name: util argv[0]
+ *
+ * Initialize private color control struct and initialize the colors
+ * status. The color schemes are parsed on demand by colors_get_scheme().
+ *
+ * Returns: >0 on success.
+ */
+int colors_init(int mode, const char *name)
+{
+ int ready = -1;
+ struct ul_color_ctl *cc = &ul_colors;
+
+ cc->utilname = name;
+
+ termcolors_init_debug();
+
+ if (mode != UL_COLORMODE_ALWAYS && !isatty(STDOUT_FILENO))
+ cc->mode = UL_COLORMODE_NEVER;
+ else
+ cc->mode = mode;
+
+ if (cc->mode == UL_COLORMODE_UNDEF
+ && (ready = colors_terminal_is_ready())) {
+ int rc = colors_read_configuration(cc);
+ if (rc)
+ cc->mode = UL_COLORMODE_DEFAULT;
+ else {
+
+ /* evaluate scores */
+ if (cc->scores[UL_COLORFILE_DISABLE] >
+ cc->scores[UL_COLORFILE_ENABLE])
+ cc->mode = UL_COLORMODE_NEVER;
+ else
+ cc->mode = UL_COLORMODE_DEFAULT;
+
+ atexit(colors_deinit);
+ }
+ }
+
+ switch (cc->mode) {
+ case UL_COLORMODE_AUTO:
+ cc->has_colors = ready == -1 ? colors_terminal_is_ready() : ready;
+ break;
+ case UL_COLORMODE_ALWAYS:
+ cc->has_colors = 1;
+ break;
+ case UL_COLORMODE_NEVER:
+ default:
+ cc->has_colors = 0;
+ }
+
+ ON_DBG(CONF, colors_debug(cc));
+
+ return cc->has_colors;
+}
+
+/*
+ * Temporary disable colors (this setting is independent on terminal-colors.d/)
+ */
+void colors_off(void)
+{
+ ul_colors.disabled = 1;
+}
+
+/*
+ * Enable colors
+ */
+void colors_on(void)
+{
+ ul_colors.disabled = 0;
+}
+
+/*
+ * Is terminal-colors.d/ configured to use colors?
+ */
+int colors_wanted(void)
+{
+ return ul_colors.has_colors;
+}
+
+/*
+ * Returns mode
+ */
+int colors_mode(void)
+{
+ return ul_colors.mode;
+}
+
+/*
+ * Enable @seq color
+ */
+void color_fenable(const char *seq, FILE *f)
+{
+ if (!ul_colors.disabled && ul_colors.has_colors && seq)
+ fputs(seq, f);
+}
+
+/*
+ * Returns escape sequence by logical @name, if undefined then returns @dflt.
+ */
+const char *color_scheme_get_sequence(const char *name, const char *dflt)
+{
+ struct ul_color_scheme *cs;
+
+ if (ul_colors.disabled || !ul_colors.has_colors)
+ return NULL;
+
+ cs = colors_get_scheme(&ul_colors, name);
+ return cs && cs->seq ? cs->seq : dflt;
+}
+
+/*
+ * Enable color by logical @name, if undefined enable @dflt.
+ */
+void color_scheme_fenable(const char *name, const char *dflt, FILE *f)
+{
+ const char *seq = color_scheme_get_sequence(name, dflt);
+
+ if (!seq)
+ return;
+ color_fenable(seq, f);
+}
+
+
+/*
+ * Disable previously enabled color
+ */
+void color_fdisable(FILE *f)
+{
+ if (!ul_colors.disabled && ul_colors.has_colors)
+ fputs(UL_COLOR_RESET, f);
+}
+
+/*
+ * Parses @str to return UL_COLORMODE_*
+ */
+int colormode_from_string(const char *str)
+{
+ size_t i;
+ static const char *modes[] = {
+ [UL_COLORMODE_AUTO] = "auto",
+ [UL_COLORMODE_NEVER] = "never",
+ [UL_COLORMODE_ALWAYS] = "always",
+ [UL_COLORMODE_UNDEF] = ""
+ };
+
+ if (!str || !*str)
+ return -EINVAL;
+
+ assert(ARRAY_SIZE(modes) == __UL_NCOLORMODES);
+
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ if (strcasecmp(str, modes[i]) == 0)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Parses @str and exit(EXIT_FAILURE) on error
+ */
+int colormode_or_err(const char *str, const char *errmsg)
+{
+ const char *p = str && *str == '=' ? str + 1 : str;
+ int colormode;
+
+ colormode = colormode_from_string(p);
+ if (colormode < 0)
+ errx(EXIT_FAILURE, "%s: '%s'", errmsg, p);
+
+ return colormode;
+}
+
+#ifdef TEST_PROGRAM_COLORS
+# include <getopt.h>
+int main(int argc, char *argv[])
+{
+ static const struct option longopts[] = {
+ { "mode", required_argument, NULL, 'm' },
+ { "color", required_argument, NULL, 'c' },
+ { "color-scheme", required_argument, NULL, 'C' },
+ { "name", required_argument, NULL, 'n' },
+ { NULL, 0, NULL, 0 }
+ };
+ int c, mode = UL_COLORMODE_UNDEF; /* default */
+ const char *color = "red", *name = NULL, *color_scheme = NULL;
+ const char *seq = NULL;
+
+ while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ color = optarg;
+ break;
+ case 'C':
+ color_scheme = optarg;
+ break;
+ case 'm':
+ mode = colormode_or_err(optarg, "unsupported color mode");
+ break;
+ case 'n':
+ name = optarg;
+ break;
+ default:
+ fprintf(stderr, "usage: %s [options]\n"
+ " -m, --mode <auto|never|always> default is undefined\n"
+ " -c, --color <red|blue|...> color for the test message\n"
+ " -C, --color-scheme <name> color for the test message\n"
+ " -n, --name <utilname> util name\n",
+ program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+ }
+
+ colors_init(mode, name ? name : program_invocation_short_name);
+
+ seq = color_sequence_from_colorname(color);
+
+ if (color_scheme)
+ color_scheme_enable(color_scheme, seq);
+ else
+ color_enable(seq);
+ printf("Hello World!");
+ color_disable();
+ fputc('\n', stdout);
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_COLORS */
+
diff --git a/src/utils/lib/cpuset.c b/src/utils/lib/cpuset.c
new file mode 100644
index 0000000..2847db8
--- /dev/null
+++ b/src/utils/lib/cpuset.c
@@ -0,0 +1,413 @@
+/*
+ * Terminology:
+ *
+ * cpuset - (libc) cpu_set_t data structure represents set of CPUs
+ * cpumask - string with hex mask (e.g. "0x00000001")
+ * cpulist - string with CPU ranges (e.g. "0-3,5,7,8")
+ *
+ * Based on code from taskset.c and Linux kernel.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/syscall.h>
+
+#include "cpuset.h"
+#include "c.h"
+
+static inline int val_to_char(int v)
+{
+ if (v >= 0 && v < 10)
+ return '0' + v;
+ if (v >= 10 && v < 16)
+ return ('a' - 10) + v;
+ return -1;
+}
+
+static inline int char_to_val(int c)
+{
+ int cl;
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ cl = tolower(c);
+ if (cl >= 'a' && cl <= 'f')
+ return cl + (10 - 'a');
+ return -1;
+}
+
+static const char *nexttoken(const char *q, int sep)
+{
+ if (q)
+ q = strchr(q, sep);
+ if (q)
+ q++;
+ return q;
+}
+
+/*
+ * Number of bits in a CPU bitmask on current system
+ */
+int get_max_number_of_cpus(void)
+{
+#ifdef SYS_sched_getaffinity
+ int n, cpus = 2048;
+ size_t setsize;
+ cpu_set_t *set = cpuset_alloc(cpus, &setsize, NULL);
+
+ if (!set)
+ return -1; /* error */
+
+ for (;;) {
+ CPU_ZERO_S(setsize, set);
+
+ /* the library version does not return size of cpumask_t */
+ n = syscall(SYS_sched_getaffinity, 0, setsize, set);
+
+ if (n < 0 && errno == EINVAL && cpus < 1024 * 1024) {
+ cpuset_free(set);
+ cpus *= 2;
+ set = cpuset_alloc(cpus, &setsize, NULL);
+ if (!set)
+ return -1; /* error */
+ continue;
+ }
+ cpuset_free(set);
+ return n * 8;
+ }
+#endif
+ return -1;
+}
+
+/*
+ * Allocates a new set for ncpus and returns size in bytes and size in bits
+ */
+cpu_set_t *cpuset_alloc(int ncpus, size_t *setsize, size_t *nbits)
+{
+ cpu_set_t *set = CPU_ALLOC(ncpus);
+
+ if (!set)
+ return NULL;
+ if (setsize)
+ *setsize = CPU_ALLOC_SIZE(ncpus);
+ if (nbits)
+ *nbits = cpuset_nbits(CPU_ALLOC_SIZE(ncpus));
+ return set;
+}
+
+void cpuset_free(cpu_set_t *set)
+{
+ CPU_FREE(set);
+}
+
+#if !HAVE_DECL_CPU_ALLOC
+/* Please, use CPU_COUNT_S() macro. This is fallback */
+int __cpuset_count_s(size_t setsize, const cpu_set_t *set)
+{
+ int s = 0;
+ const __cpu_mask *p = set->__bits;
+ const __cpu_mask *end = &set->__bits[setsize / sizeof (__cpu_mask)];
+
+ while (p < end) {
+ __cpu_mask l = *p++;
+
+ if (l == 0)
+ continue;
+# if LONG_BIT > 32
+ l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul);
+ l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul);
+ l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful);
+ l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful);
+ l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful);
+ l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful);
+# else
+ l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul);
+ l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul);
+ l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful);
+ l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful);
+ l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful);
+# endif
+ s += l;
+ }
+ return s;
+}
+#endif
+
+/*
+ * Returns human readable representation of the cpuset. The output format is
+ * a list of CPUs with ranges (for example, "0,1,3-9").
+ */
+char *cpulist_create(char *str, size_t len,
+ cpu_set_t *set, size_t setsize)
+{
+ size_t i;
+ char *ptr = str;
+ int entry_made = 0;
+ size_t max = cpuset_nbits(setsize);
+
+ for (i = 0; i < max; i++) {
+ if (CPU_ISSET_S(i, setsize, set)) {
+ int rlen;
+ size_t j, run = 0;
+ entry_made = 1;
+ for (j = i + 1; j < max; j++) {
+ if (CPU_ISSET_S(j, setsize, set))
+ run++;
+ else
+ break;
+ }
+ if (!run)
+ rlen = snprintf(ptr, len, "%zu,", i);
+ else if (run == 1) {
+ rlen = snprintf(ptr, len, "%zu,%zu,", i, i + 1);
+ i++;
+ } else {
+ rlen = snprintf(ptr, len, "%zu-%zu,", i, i + run);
+ i += run;
+ }
+ if (rlen < 0 || (size_t) rlen >= len)
+ return NULL;
+ ptr += rlen;
+ len -= rlen;
+ }
+ }
+ ptr -= entry_made;
+ *ptr = '\0';
+
+ return str;
+}
+
+/*
+ * Returns string with CPU mask.
+ */
+char *cpumask_create(char *str, size_t len,
+ cpu_set_t *set, size_t setsize)
+{
+ char *ptr = str;
+ char *ret = NULL;
+ int cpu;
+
+ for (cpu = cpuset_nbits(setsize) - 4; cpu >= 0; cpu -= 4) {
+ char val = 0;
+
+ if (len == (size_t) (ptr - str))
+ break;
+
+ if (CPU_ISSET_S(cpu, setsize, set))
+ val |= 1;
+ if (CPU_ISSET_S(cpu + 1, setsize, set))
+ val |= 2;
+ if (CPU_ISSET_S(cpu + 2, setsize, set))
+ val |= 4;
+ if (CPU_ISSET_S(cpu + 3, setsize, set))
+ val |= 8;
+
+ if (!ret && val)
+ ret = ptr;
+ *ptr++ = val_to_char(val);
+ }
+ *ptr = '\0';
+ return ret ? ret : ptr - 1;
+}
+
+/*
+ * Parses string with CPUs mask.
+ */
+int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize)
+{
+ int len = strlen(str);
+ const char *ptr = str + len - 1;
+ int cpu = 0;
+
+ /* skip 0x, it's all hex anyway */
+ if (len > 1 && !memcmp(str, "0x", 2L))
+ str += 2;
+
+ CPU_ZERO_S(setsize, set);
+
+ while (ptr >= str) {
+ char val;
+
+ /* cpu masks in /sys uses comma as a separator */
+ if (*ptr == ',')
+ ptr--;
+
+ val = char_to_val(*ptr);
+ if (val == (char) -1)
+ return -1;
+ if (val & 1)
+ CPU_SET_S(cpu, setsize, set);
+ if (val & 2)
+ CPU_SET_S(cpu + 1, setsize, set);
+ if (val & 4)
+ CPU_SET_S(cpu + 2, setsize, set);
+ if (val & 8)
+ CPU_SET_S(cpu + 3, setsize, set);
+ ptr--;
+ cpu += 4;
+ }
+
+ return 0;
+}
+
+static int nextnumber(const char *str, char **end, unsigned int *result)
+{
+ errno = 0;
+ if (str == NULL || *str == '\0' || !isdigit(*str))
+ return -EINVAL;
+ *result = (unsigned int) strtoul(str, end, 10);
+ if (errno)
+ return -errno;
+ if (str == *end)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * Parses string with list of CPU ranges.
+ * Returns 0 on success.
+ * Returns 1 on error.
+ * Returns 2 if fail is set and a cpu number passed in the list doesn't fit
+ * into the cpu_set. If fail is not set cpu numbers that do not fit are
+ * ignored and 0 is returned instead.
+ */
+int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail)
+{
+ size_t max = cpuset_nbits(setsize);
+ const char *p, *q;
+ char *end = NULL;
+
+ q = str;
+ CPU_ZERO_S(setsize, set);
+
+ while (p = q, q = nexttoken(q, ','), p) {
+ unsigned int a; /* beginning of range */
+ unsigned int b; /* end of range */
+ unsigned int s; /* stride */
+ const char *c1, *c2;
+
+ if (nextnumber(p, &end, &a) != 0)
+ return 1;
+ b = a;
+ s = 1;
+ p = end;
+
+ c1 = nexttoken(p, '-');
+ c2 = nexttoken(p, ',');
+
+ if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+ if (nextnumber(c1, &end, &b) != 0)
+ return 1;
+
+ c1 = end && *end ? nexttoken(end, ':') : NULL;
+
+ if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+ if (nextnumber(c1, &end, &s) != 0)
+ return 1;
+ if (s == 0)
+ return 1;
+ }
+ }
+
+ if (!(a <= b))
+ return 1;
+ while (a <= b) {
+ if (fail && (a >= max))
+ return 2;
+ CPU_SET_S(a, setsize, set);
+ a += s;
+ }
+ }
+
+ if (end && *end)
+ return 1;
+ return 0;
+}
+
+#ifdef TEST_PROGRAM_CPUSET
+
+#include <getopt.h>
+
+int main(int argc, char *argv[])
+{
+ cpu_set_t *set;
+ size_t setsize, buflen, nbits;
+ char *buf, *mask = NULL, *range = NULL;
+ int ncpus = 2048, rc, c;
+
+ static const struct option longopts[] = {
+ { "ncpus", 1, NULL, 'n' },
+ { "mask", 1, NULL, 'm' },
+ { "range", 1, NULL, 'r' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "n:m:r:", longopts, NULL)) != -1) {
+ switch(c) {
+ case 'n':
+ ncpus = atoi(optarg);
+ break;
+ case 'm':
+ mask = strdup(optarg);
+ break;
+ case 'r':
+ range = strdup(optarg);
+ break;
+ default:
+ goto usage_err;
+ }
+ }
+
+ if (!mask && !range)
+ goto usage_err;
+
+ set = cpuset_alloc(ncpus, &setsize, &nbits);
+ if (!set)
+ err(EXIT_FAILURE, "failed to allocate cpu set");
+
+ /*
+ fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n",
+ ncpus, nbits, setsize);
+ */
+
+ buflen = 7 * nbits;
+ buf = malloc(buflen);
+ if (!buf)
+ err(EXIT_FAILURE, "failed to allocate cpu set buffer");
+
+ if (mask)
+ rc = cpumask_parse(mask, set, setsize);
+ else
+ rc = cpulist_parse(range, set, setsize, 0);
+
+ if (rc)
+ errx(EXIT_FAILURE, "failed to parse string: %s", mask ? : range);
+
+ printf("%-15s = %15s ", mask ? : range,
+ cpumask_create(buf, buflen, set, setsize));
+ printf("[%s]\n", cpulist_create(buf, buflen, set, setsize));
+
+ free(buf);
+ free(mask);
+ free(range);
+ cpuset_free(set);
+
+ return EXIT_SUCCESS;
+
+usage_err:
+ fprintf(stderr,
+ "usage: %s [--ncpus <num>] --mask <mask> | --range <list>\n",
+ program_invocation_short_name);
+ exit(EXIT_FAILURE);
+}
+#endif
diff --git a/src/utils/lib/crc32.c b/src/utils/lib/crc32.c
new file mode 100644
index 0000000..824693d
--- /dev/null
+++ b/src/utils/lib/crc32.c
@@ -0,0 +1,142 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1.
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way,
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to high-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly.
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera-
+ * tions for all combinations of data and CRC register values.
+ *
+ * The values must be right-shifted by eight bits by the "updcrc"
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions.
+ * polynomial $edb88320
+ *
+ */
+
+#include <stdio.h>
+
+#include "crc32.h"
+
+
+static const uint32_t crc32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+static inline uint32_t crc32_add_char(uint32_t crc, unsigned char c)
+{
+ return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8);
+}
+
+/*
+ * This a generic crc32() function, it takes seed as an argument,
+ * and does __not__ xor at the end. Then individual users can do
+ * whatever they need.
+ */
+uint32_t ul_crc32(uint32_t seed, const unsigned char *buf, size_t len)
+{
+ uint32_t crc = seed;
+ const unsigned char *p = buf;
+
+ while (len) {
+ crc = crc32_add_char(crc, *p++);
+ len--;
+ }
+
+ return crc;
+}
+
+uint32_t ul_crc32_exclude_offset(uint32_t seed, const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len)
+{
+ uint32_t crc = seed;
+ const unsigned char *p = buf;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ unsigned char x = *p++;
+
+ if (i >= exclude_off && i < exclude_off + exclude_len)
+ x = 0;
+
+ crc = crc32_add_char(crc, x);
+ }
+
+ return crc;
+}
+
diff --git a/src/utils/lib/crc32c.c b/src/utils/lib/crc32c.c
new file mode 100644
index 0000000..49e7543
--- /dev/null
+++ b/src/utils/lib/crc32c.c
@@ -0,0 +1,102 @@
+/*
+ * This code is from freebsd/sys/libkern/crc32.c
+ *
+ * Simplest table-based crc32c. Performance is not important
+ * for checking crcs on superblocks
+ */
+
+/*-
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+#include "crc32c.h"
+
+static const uint32_t crc32Table[256] = {
+ 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+ 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+ 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+ 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+ 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+ 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+ 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+ 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+ 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+ 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+ 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+ 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+ 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+ 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+ 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+ 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+ 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+ 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+ 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+ 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+ 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+ 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+ 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+ 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+ 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+ 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+ 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+ 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+ 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+ 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+ 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+ 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+ 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+ 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+ 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+ 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+ 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+ 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+ 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+ 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+ 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+ 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+ 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+ 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+ 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+ 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+ 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+ 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+ 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+ 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+ 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+ 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+ 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+ 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+ 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+ 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+ 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+ 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+ 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+ 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+ 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+ 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+ 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+ 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
+};
+
+/*
+ *This was singletable_crc32c() in bsd
+ *
+ * If you will not be passing crc back into this function to process more bytes,
+ * the answer is:
+ *
+ * crc = crc32c(~0L, buf, size);
+ * [ crc = crc32c(crc, buf, size); ]
+ * crc ^= ~0L
+ *
+ */
+uint32_t
+crc32c(uint32_t crc, const void *buf, size_t size)
+{
+ const uint8_t *p = buf;
+
+ while (size--)
+ crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+
+ return crc;
+}
diff --git a/src/utils/lib/encode.c b/src/utils/lib/encode.c
new file mode 100644
index 0000000..10b5971
--- /dev/null
+++ b/src/utils/lib/encode.c
@@ -0,0 +1,79 @@
+/*
+ * Based on code from libblkid,
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2020 Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include "c.h"
+#include "encode.h"
+
+size_t ul_encode_to_utf8(int enc, unsigned char *dest, size_t len,
+ const unsigned char *src, size_t count)
+{
+ size_t i, j;
+ uint32_t c;
+ uint16_t c2;
+
+ for (j = i = 0; i < count; i++) {
+ if (enc == UL_ENCODE_UTF16LE) {
+ if (i+2 > count)
+ break;
+ c = (src[i+1] << 8) | src[i];
+ i++;
+ } else if (enc == UL_ENCODE_UTF16BE) {
+ if (i+2 > count)
+ break;
+ c = (src[i] << 8) | src[i+1];
+ i++;
+ } else if (enc == UL_ENCODE_LATIN1) {
+ c = src[i];
+ } else {
+ return 0;
+ }
+ if ((enc == UL_ENCODE_UTF16LE || enc == UL_ENCODE_UTF16BE) &&
+ c >= 0xD800 && c <= 0xDBFF && i+2 < count) {
+ if (enc == UL_ENCODE_UTF16LE)
+ c2 = (src[i+2] << 8) | src[i+1];
+ else
+ c2 = (src[i+1] << 8) | src[i+2];
+ if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
+ c = 0x10000 + ((c - 0xD800) << 10) + (c2 - 0xDC00);
+ i += 2;
+ }
+ }
+ if (c == 0) {
+ dest[j] = '\0';
+ break;
+ }
+
+ if (c < 0x80) {
+ if (j+1 >= len)
+ break;
+ dest[j++] = (uint8_t) c;
+ } else if (c < 0x800) {
+ if (j+2 >= len)
+ break;
+ dest[j++] = (uint8_t) (0xc0 | (c >> 6));
+ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ } else if (c < 0x10000) {
+ if (j+3 >= len)
+ break;
+ dest[j++] = (uint8_t) (0xe0 | (c >> 12));
+ dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ } else {
+ if (j+4 >= len)
+ break;
+ dest[j++] = (uint8_t) (0xf0 | (c >> 18));
+ dest[j++] = (uint8_t) (0x80 | ((c >> 12) & 0x3f));
+ dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+ dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
+ }
+ }
+ dest[j] = '\0';
+ return j;
+}
diff --git a/src/utils/lib/env.c b/src/utils/lib/env.c
new file mode 100644
index 0000000..c26a5be
--- /dev/null
+++ b/src/utils/lib/env.c
@@ -0,0 +1,238 @@
+/*
+ * Security checks of environment
+ * Added from shadow-utils package
+ * by Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "env.h"
+
+#ifndef HAVE_ENVIRON_DECL
+extern char **environ;
+#endif
+
+static char * const forbid[] = {
+ "BASH_ENV=", /* GNU creeping featurism strikes again... */
+ "ENV=",
+ "HOME=",
+ "IFS=",
+ "KRB_CONF=",
+ "LD_", /* anything with the LD_ prefix */
+ "LIBPATH=",
+ "MAIL=",
+ "NLSPATH=",
+ "PATH=",
+ "SHELL=",
+ "SHLIB_PATH=",
+ (char *) 0
+};
+
+/* these are allowed, but with no slashes inside
+ (to work around security problems in GNU gettext) */
+static char * const noslash[] = {
+ "LANG=",
+ "LANGUAGE=",
+ "LC_", /* anything with the LC_ prefix */
+ (char *) 0
+};
+
+
+struct ul_env_list {
+ char *env;
+ struct ul_env_list *next;
+};
+
+/*
+ * Saves @name env.varable to @ls, returns pointer to the new head of the list.
+ */
+static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str)
+{
+ struct ul_env_list *ls;
+ char *p;
+ size_t sz = 0;
+
+ if (!str || !*str)
+ return ls0;
+
+ sz = strlen(str) + 1;
+ p = malloc(sizeof(struct ul_env_list) + sz);
+
+ ls = (struct ul_env_list *) p;
+ p += sizeof(struct ul_env_list);
+ memcpy(p, str, sz);
+ ls->env = p;
+
+ ls->next = ls0;
+ return ls;
+}
+
+/*
+ * Use setenv() for all stuff in @ls.
+ *
+ * It would be possible to use putenv(), but we want to keep @ls free()-able.
+ */
+int env_list_setenv(struct ul_env_list *ls)
+{
+ int rc = 0;
+
+ while (ls && rc == 0) {
+ if (ls->env) {
+ char *val = strchr(ls->env, '=');
+ if (!val)
+ continue;
+ *val = '\0';
+ rc = setenv(ls->env, val + 1, 0);
+ *val = '=';
+ }
+ ls = ls->next;
+ }
+ return rc;
+}
+
+void env_list_free(struct ul_env_list *ls)
+{
+ while (ls) {
+ struct ul_env_list *x = ls;
+ ls = ls->next;
+ free(x);
+ }
+}
+
+/*
+ * Removes unwanted variables from environ[]. If @ls is not NULL than stores
+ * unwnated variables to the list.
+ */
+void __sanitize_env(struct ul_env_list **org)
+{
+ char **envp = environ;
+ char * const *bad;
+ char **cur;
+ int last = 0;
+
+ for (cur = envp; *cur; cur++)
+ last++;
+
+ for (cur = envp; *cur; cur++) {
+ for (bad = forbid; *bad; bad++) {
+ if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
+ if (org)
+ *org = env_list_add(*org, *cur);
+ last = remote_entry(envp, cur - envp, last);
+ cur--;
+ break;
+ }
+ }
+ }
+
+ for (cur = envp; *cur; cur++) {
+ for (bad = noslash; *bad; bad++) {
+ if (strncmp(*cur, *bad, strlen(*bad)) != 0)
+ continue;
+ if (!strchr(*cur, '/'))
+ continue; /* OK */
+ if (org)
+ *org = env_list_add(*org, *cur);
+ last = remote_entry(envp, cur - envp, last);
+ cur--;
+ break;
+ }
+ }
+}
+
+void sanitize_env(void)
+{
+ __sanitize_env(NULL);
+}
+
+char *safe_getenv(const char *arg)
+{
+ uid_t ruid = getuid();
+
+ if (ruid != 0 || (ruid != geteuid()) || (getgid() != getegid()))
+ return NULL;
+#ifdef HAVE_PRCTL
+ if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+ if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#endif
+#endif
+#ifdef HAVE_SECURE_GETENV
+return secure_getenv(arg);
+#elif HAVE___SECURE_GETENV
+ return __secure_getenv(arg);
+#else
+ return getenv(arg);
+#endif
+}
+
+#ifdef TEST_PROGRAM
+int main(void)
+{
+ char *const *bad;
+ char copy[32];
+ char *p;
+ int retval = EXIT_SUCCESS;
+ struct ul_env_list *removed = NULL;
+
+ for (bad = forbid; *bad; bad++) {
+ strcpy(copy, *bad);
+ p = strchr(copy, '=');
+ if (p)
+ *p = '\0';
+ setenv(copy, copy, 1);
+ }
+
+ /* removed */
+ __sanitize_env(&removed);
+
+ /* check removal */
+ for (bad = forbid; *bad; bad++) {
+ strcpy(copy, *bad);
+ p = strchr(copy, '=');
+ if (p)
+ *p = '\0';
+ p = getenv(copy);
+ if (p) {
+ warnx("%s was not removed", copy);
+ retval = EXIT_FAILURE;
+ }
+ }
+
+ /* restore removed */
+ env_list_setenv(removed);
+
+ /* check restore */
+ for (bad = forbid; *bad; bad++) {
+ strcpy(copy, *bad);
+ p = strchr(copy, '=');
+ if (p)
+ *p = '\0';
+ p = getenv(copy);
+ if (!p) {
+ warnx("%s was not restored", copy);
+ retval = EXIT_FAILURE;
+ }
+ }
+
+ env_list_free(removed);
+
+ return retval;
+}
+#endif
diff --git a/src/utils/lib/exec_shell.c b/src/utils/lib/exec_shell.c
new file mode 100644
index 0000000..18798eb
--- /dev/null
+++ b/src/utils/lib/exec_shell.c
@@ -0,0 +1,51 @@
+/*
+ * exec_shell() - launch a shell, else exit!
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <libgen.h>
+
+#include "nls.h"
+#include "c.h"
+#include "xalloc.h"
+
+#include "exec_shell.h"
+
+#define DEFAULT_SHELL "/bin/sh"
+
+void __attribute__((__noreturn__)) exec_shell(void)
+{
+ const char *shell = getenv("SHELL");
+ char *shellc;
+ const char *shell_basename;
+ char *arg0;
+
+ if (!shell)
+ shell = DEFAULT_SHELL;
+
+ shellc = xstrdup(shell);
+ shell_basename = basename(shellc);
+ arg0 = xmalloc(strlen(shell_basename) + 2);
+ arg0[0] = '-';
+ strcpy(arg0 + 1, shell_basename);
+
+ execl(shell, arg0, NULL);
+ errexec(shell);
+}
diff --git a/src/utils/lib/fileutils.c b/src/utils/lib/fileutils.c
new file mode 100644
index 0000000..3ca43c1
--- /dev/null
+++ b/src/utils/lib/fileutils.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include "c.h"
+#include "fileutils.h"
+#include "pathnames.h"
+
+int mkstemp_cloexec(char *template)
+{
+#ifdef HAVE_MKOSTEMP
+ return mkostemp(template, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC);
+#else
+ int fd, old_flags, errno_save;
+
+ fd = mkstemp(template);
+ if (fd < 0)
+ return fd;
+
+ old_flags = fcntl(fd, F_GETFD, 0);
+ if (old_flags < 0)
+ goto unwind;
+ if (fcntl(fd, F_SETFD, old_flags | O_CLOEXEC) < 0)
+ goto unwind;
+
+ return fd;
+
+unwind:
+ errno_save = errno;
+ unlink(template);
+ close(fd);
+ errno = errno_save;
+
+ return -1;
+#endif
+}
+
+/* Create open temporary file in safe way. Please notice that the
+ * file permissions are -rw------- by default. */
+int xmkstemp(char **tmpname, const char *dir, const char *prefix)
+{
+ char *localtmp;
+ const char *tmpenv;
+ mode_t old_mode;
+ int fd, rc;
+
+ /* Some use cases must be capable of being moved atomically
+ * with rename(2), which is the reason why dir is here. */
+ tmpenv = dir ? dir : getenv("TMPDIR");
+ if (!tmpenv)
+ tmpenv = _PATH_TMP;
+
+ rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, prefix);
+ if (rc < 0)
+ return -1;
+
+ old_mode = umask(077);
+ fd = mkstemp_cloexec(localtmp);
+ umask(old_mode);
+ if (fd == -1) {
+ free(localtmp);
+ localtmp = NULL;
+ }
+ *tmpname = localtmp;
+ return fd;
+}
+
+int dup_fd_cloexec(int oldfd, int lowfd)
+{
+ int fd, flags, errno_save;
+
+#ifdef F_DUPFD_CLOEXEC
+ fd = fcntl(oldfd, F_DUPFD_CLOEXEC, lowfd);
+ if (fd >= 0)
+ return fd;
+#endif
+
+ fd = dup(oldfd);
+ if (fd < 0)
+ return fd;
+
+ flags = fcntl(fd, F_GETFD);
+ if (flags < 0)
+ goto unwind;
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
+ goto unwind;
+
+ return fd;
+
+unwind:
+ errno_save = errno;
+ close(fd);
+ errno = errno_save;
+
+ return -1;
+}
+
+/*
+ * portable getdtablesize()
+ */
+int get_fd_tabsize(void)
+{
+ int m;
+
+#if defined(HAVE_GETDTABLESIZE)
+ m = getdtablesize();
+#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
+ struct rlimit rl;
+
+ getrlimit(RLIMIT_NOFILE, &rl);
+ m = rl.rlim_cur;
+#elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
+ m = sysconf(_SC_OPEN_MAX);
+#else
+ m = OPEN_MAX;
+#endif
+ return m;
+}
+
+static inline int in_set(int x, const int set[], size_t setsz)
+{
+ size_t i;
+
+ for (i = 0; i < setsz; i++) {
+ if (set[i] == x)
+ return 1;
+ }
+ return 0;
+}
+
+void close_all_fds(const int exclude[], size_t exsz)
+{
+ struct dirent *d;
+ DIR *dir;
+
+ dir = opendir(_PATH_PROC_FDDIR);
+ if (dir) {
+ while ((d = xreaddir(dir))) {
+ char *end;
+ int fd;
+
+ errno = 0;
+ fd = strtol(d->d_name, &end, 10);
+
+ if (errno || end == d->d_name || !end || *end)
+ continue;
+ if (dirfd(dir) == fd)
+ continue;
+ if (in_set(fd, exclude, exsz))
+ continue;
+ close(fd);
+ }
+ closedir(dir);
+ } else {
+ int fd, tbsz = get_fd_tabsize();
+
+ for (fd = 0; fd < tbsz; fd++) {
+ if (!in_set(fd, exclude, exsz))
+ close(fd);
+ }
+ }
+}
+
+#ifdef TEST_PROGRAM_FILEUTILS
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ errx(EXIT_FAILURE, "Usage %s --{mkstemp,close-fds}", argv[0]);
+
+ if (strcmp(argv[1], "--mkstemp") == 0) {
+ FILE *f;
+ char *tmpname;
+ f = xfmkstemp(&tmpname, NULL, "test");
+ unlink(tmpname);
+ free(tmpname);
+ fclose(f);
+
+ } else if (strcmp(argv[1], "--close-fds") == 0) {
+ static const int wanted_fds[] = {
+ STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO
+ };
+
+ ignore_result( dup(STDIN_FILENO) );
+ ignore_result( dup(STDIN_FILENO) );
+ ignore_result( dup(STDIN_FILENO) );
+
+ close_all_fds(wanted_fds, ARRAY_SIZE(wanted_fds));
+ }
+ return EXIT_SUCCESS;
+}
+#endif
+
+
+int mkdir_p(const char *path, mode_t mode)
+{
+ char *p, *dir;
+ int rc = 0;
+
+ if (!path || !*path)
+ return -EINVAL;
+
+ dir = p = strdup(path);
+ if (!dir)
+ return -ENOMEM;
+
+ if (*p == '/')
+ p++;
+
+ while (p && *p) {
+ char *e = strchr(p, '/');
+ if (e)
+ *e = '\0';
+ if (*p) {
+ rc = mkdir(dir, mode);
+ if (rc && errno != EEXIST)
+ break;
+ rc = 0;
+ }
+ if (!e)
+ break;
+ *e = '/';
+ p = e + 1;
+ }
+
+ free(dir);
+ return rc;
+}
+
+/* returns basename and keeps dirname in the @path, if @path is "/" (root)
+ * then returns empty string */
+char *stripoff_last_component(char *path)
+{
+ char *p = path ? strrchr(path, '/') : NULL;
+
+ if (!p)
+ return NULL;
+ *p = '\0';
+ return p + 1;
+}
diff --git a/src/utils/lib/idcache.c b/src/utils/lib/idcache.c
new file mode 100644
index 0000000..5550223
--- /dev/null
+++ b/src/utils/lib/idcache.c
@@ -0,0 +1,117 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include <wchar.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#include "c.h"
+#include "idcache.h"
+
+struct identry *get_id(struct idcache *ic, unsigned long int id)
+{
+ struct identry *ent;
+
+ if (!ic)
+ return NULL;
+
+ for (ent = ic->ent; ent; ent = ent->next) {
+ if (ent->id == id)
+ return ent;
+ }
+
+ return NULL;
+}
+
+struct idcache *new_idcache(void)
+{
+ return calloc(1, sizeof(struct idcache));
+}
+
+void free_idcache(struct idcache *ic)
+{
+ struct identry *ent = ic->ent;
+
+ while (ent) {
+ struct identry *next = ent->next;
+ free(ent->name);
+ free(ent);
+ ent = next;
+ }
+
+ free(ic);
+}
+
+static void add_id(struct idcache *ic, char *name, unsigned long int id)
+{
+ struct identry *ent, *x;
+ int w = 0;
+
+ ent = calloc(1, sizeof(struct identry));
+ if (!ent)
+ return;
+ ent->id = id;
+
+ if (name) {
+#ifdef HAVE_WIDECHAR
+ wchar_t wc[LOGIN_NAME_MAX + 1];
+
+ if (mbstowcs(wc, name, LOGIN_NAME_MAX) > 0) {
+ wc[LOGIN_NAME_MAX] = '\0';
+ w = wcswidth(wc, LOGIN_NAME_MAX);
+ }
+ else
+#endif
+ w = strlen(name);
+ }
+
+ /* note, we ignore names with non-printable widechars */
+ if (w > 0) {
+ ent->name = strdup(name);
+ if (!ent->name) {
+ free(ent);
+ return;
+ }
+ } else {
+ if (asprintf(&ent->name, "%lu", id) < 0) {
+ free(ent);
+ return;
+ }
+ }
+
+ for (x = ic->ent; x && x->next; x = x->next);
+
+ if (x)
+ x->next = ent;
+ else
+ ic->ent = ent;
+
+ if (w <= 0)
+ w = ent->name ? strlen(ent->name) : 0;
+ ic->width = ic->width < w ? w : ic->width;
+}
+
+void add_uid(struct idcache *cache, unsigned long int id)
+{
+ struct identry *ent= get_id(cache, id);
+
+ if (!ent) {
+ struct passwd *pw = getpwuid((uid_t) id);
+ add_id(cache, pw ? pw->pw_name : NULL, id);
+ }
+}
+
+void add_gid(struct idcache *cache, unsigned long int id)
+{
+ struct identry *ent = get_id(cache, id);
+
+ if (!ent) {
+ struct group *gr = getgrgid((gid_t) id);
+ add_id(cache, gr ? gr->gr_name : NULL, id);
+ }
+}
+
diff --git a/src/utils/lib/ismounted.c b/src/utils/lib/ismounted.c
new file mode 100644
index 0000000..9a20b23
--- /dev/null
+++ b/src/utils/lib/ismounted.c
@@ -0,0 +1,396 @@
+/*
+ * ismounted.c --- Check to see if the filesystem was mounted
+ *
+ * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o.
+ *
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#ifndef __linux__
+# ifdef HAVE_SYS_UCRED_H
+# include <sys/ucred.h>
+# endif
+# ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+# endif
+#endif
+
+#include "pathnames.h"
+#include "strutils.h"
+#include "ismounted.h"
+#include "c.h"
+#ifdef __linux__
+# include "loopdev.h"
+#endif
+
+
+
+#ifdef HAVE_MNTENT_H
+/*
+ * Helper function which checks a file in /etc/mtab format to see if a
+ * filesystem is mounted. Returns an error if the file doesn't exist
+ * or can't be opened.
+ */
+static int check_mntent_file(const char *mtab_file, const char *file,
+ int *mount_flags, char *mtpt, int mtlen)
+{
+ struct mntent *mnt;
+ struct stat st_buf;
+ int retval = 0;
+ dev_t file_dev=0, file_rdev=0;
+ ino_t file_ino=0;
+ FILE *f;
+ int fd;
+
+ *mount_flags = 0;
+ if ((f = setmntent (mtab_file, "r")) == NULL)
+ return errno;
+
+ if (stat(file, &st_buf) == 0) {
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ file_rdev = st_buf.st_rdev;
+#endif /* __GNU__ */
+ } else {
+ file_dev = st_buf.st_dev;
+ file_ino = st_buf.st_ino;
+ }
+ }
+
+ while ((mnt = getmntent (f)) != NULL) {
+ if (mnt->mnt_fsname[0] != '/')
+ continue;
+ if (strcmp(file, mnt->mnt_fsname) == 0)
+ break;
+ if (stat(mnt->mnt_fsname, &st_buf) != 0)
+ continue;
+
+ if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__
+ if (file_rdev && file_rdev == st_buf.st_rdev)
+ break;
+#ifdef __linux__
+ /* maybe the file is loopdev backing file */
+ if (file_dev
+ && major(st_buf.st_rdev) == LOOPDEV_MAJOR
+ && loopdev_is_used(mnt->mnt_fsname, file, 0, 0, 0))
+ break;
+#endif /* __linux__ */
+#endif /* __GNU__ */
+ } else {
+ if (file_dev && ((file_dev == st_buf.st_dev) &&
+ (file_ino == st_buf.st_ino)))
+ break;
+ }
+ }
+
+ if (mnt == NULL) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ /*
+ * Do an extra check to see if this is the root device. We
+ * can't trust /etc/mtab, and /proc/mounts will only list
+ * /dev/root for the root filesystem. Argh. Instead we
+ * check if the given device has the same major/minor number
+ * as the device that the root directory is on.
+ */
+ if (file_rdev && stat("/", &st_buf) == 0 &&
+ st_buf.st_dev == file_rdev) {
+ *mount_flags = MF_MOUNTED;
+ if (mtpt)
+ xstrncpy(mtpt, "/", mtlen);
+ goto is_root;
+ }
+#endif /* __GNU__ */
+ goto errout;
+ }
+#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
+ /* Validate the entry in case /etc/mtab is out of date */
+ /*
+ * We need to be paranoid, because some broken distributions
+ * (read: Slackware) don't initialize /etc/mtab before checking
+ * all of the non-root filesystems on the disk.
+ */
+ if (stat(mnt->mnt_dir, &st_buf) < 0) {
+ retval = errno;
+ if (retval == ENOENT) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s does not exist)\n",
+ mtab_file, mnt->mnt_dir);
+#endif /* DEBUG */
+ retval = 0;
+ }
+ goto errout;
+ }
+ if (file_rdev && (st_buf.st_dev != file_rdev)) {
+#ifdef DEBUG
+ printf("Bogus entry in %s! (%s not mounted on %s)\n",
+ mtab_file, file, mnt->mnt_dir);
+#endif /* DEBUG */
+ goto errout;
+ }
+#endif /* __GNU__ */
+ *mount_flags = MF_MOUNTED;
+
+#ifdef MNTOPT_RO
+ /* Check to see if the ro option is set */
+ if (hasmntopt(mnt, MNTOPT_RO))
+ *mount_flags |= MF_READONLY;
+#endif
+
+ if (mtpt)
+ xstrncpy(mtpt, mnt->mnt_dir, mtlen);
+ /*
+ * Check to see if we're referring to the root filesystem.
+ * If so, do a manual check to see if we can open /etc/mtab
+ * read/write, since if the root is mounted read/only, the
+ * contents of /etc/mtab may not be accurate.
+ */
+ if (!strcmp(mnt->mnt_dir, "/")) {
+is_root:
+#define TEST_FILE "/.ismount-test-file"
+ *mount_flags |= MF_ISROOT;
+ fd = open(TEST_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0600);
+ if (fd < 0) {
+ if (errno == EROFS)
+ *mount_flags |= MF_READONLY;
+ } else
+ close(fd);
+ (void) unlink(TEST_FILE);
+ }
+ retval = 0;
+errout:
+ endmntent (f);
+ return retval;
+}
+
+static int check_mntent(const char *file, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ int retval;
+
+#ifdef DEBUG
+ retval = check_mntent_file("/tmp/mtab", file, mount_flags,
+ mtpt, mtlen);
+ if (retval == 0)
+ return 0;
+#endif /* DEBUG */
+#ifdef __linux__
+ retval = check_mntent_file("/proc/mounts", file, mount_flags,
+ mtpt, mtlen);
+ if (retval == 0 && (*mount_flags != 0))
+ return 0;
+ if (access("/proc/mounts", R_OK) == 0) {
+ *mount_flags = 0;
+ return retval;
+ }
+#endif /* __linux__ */
+#if defined(MOUNTED) || defined(_PATH_MOUNTED)
+#ifndef MOUNTED
+#define MOUNTED _PATH_MOUNTED
+#endif /* MOUNTED */
+ retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
+ return retval;
+#else
+ *mount_flags = 0;
+ return 0;
+#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
+}
+
+#else
+#if defined(HAVE_GETMNTINFO)
+
+static int check_getmntinfo(const char *file, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ struct statfs *mp;
+ int len, n;
+ const char *s1;
+ char *s2;
+
+ n = getmntinfo(&mp, MNT_NOWAIT);
+ if (n == 0)
+ return errno;
+
+ len = sizeof(_PATH_DEV) - 1;
+ s1 = file;
+ if (strncmp(_PATH_DEV, s1, len) == 0)
+ s1 += len;
+
+ *mount_flags = 0;
+ while (--n >= 0) {
+ s2 = mp->f_mntfromname;
+ if (strncmp(_PATH_DEV, s2, len) == 0) {
+ s2 += len - 1;
+ *s2 = 'r';
+ }
+ if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
+ *mount_flags = MF_MOUNTED;
+ break;
+ }
+ ++mp;
+ }
+ if (mtpt)
+ xstrncpy(mtpt, mp->f_mntonname, mtlen);
+ return 0;
+}
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+
+/*
+ * Check to see if we're dealing with the swap device.
+ */
+static int is_swap_device(const char *file)
+{
+ FILE *f;
+ char buf[1024], *cp;
+ dev_t file_dev;
+ struct stat st_buf;
+ int ret = 0;
+
+ file_dev = 0;
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+ if ((stat(file, &st_buf) == 0) &&
+ S_ISBLK(st_buf.st_mode))
+ file_dev = st_buf.st_rdev;
+#endif /* __GNU__ */
+
+ if (!(f = fopen("/proc/swaps", "r" UL_CLOEXECSTR)))
+ return 0;
+ /* Skip the first line */
+ if (!fgets(buf, sizeof(buf), f))
+ goto leave;
+ if (*buf && strncmp(buf, "Filename\t", 9) != 0)
+ /* Linux <=2.6.19 contained a bug in the /proc/swaps
+ * code where the header would not be displayed
+ */
+ goto valid_first_line;
+
+ while (fgets(buf, sizeof(buf), f)) {
+valid_first_line:
+ if ((cp = strchr(buf, ' ')) != NULL)
+ *cp = 0;
+ if ((cp = strchr(buf, '\t')) != NULL)
+ *cp = 0;
+ if (strcmp(buf, file) == 0) {
+ ret++;
+ break;
+ }
+#ifndef __GNU__
+ if (file_dev && (stat(buf, &st_buf) == 0) &&
+ S_ISBLK(st_buf.st_mode) &&
+ file_dev == st_buf.st_rdev) {
+ ret++;
+ break;
+ }
+#endif /* __GNU__ */
+ }
+
+leave:
+ fclose(f);
+ return ret;
+}
+
+
+/*
+ * check_mount_point() fills determines if the device is mounted or otherwise
+ * busy, and fills in mount_flags with one or more of the following flags:
+ * MF_MOUNTED, MF_ISROOT, MF_READONLY, MF_SWAP, and MF_BUSY. If mtpt is
+ * non-NULL, the directory where the device is mounted is copied to where mtpt
+ * is pointing, up to mtlen characters.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+int check_mount_point(const char *device, int *mount_flags,
+ char *mtpt, int mtlen)
+{
+ int retval = 0;
+
+ if (is_swap_device(device)) {
+ *mount_flags = MF_MOUNTED | MF_SWAP;
+ if (mtpt && mtlen)
+ xstrncpy(mtpt, "[SWAP]", mtlen);
+ } else {
+#ifdef HAVE_MNTENT_H
+ retval = check_mntent(device, mount_flags, mtpt, mtlen);
+#else
+#ifdef HAVE_GETMNTINFO
+ retval = check_getmntinfo(device, mount_flags, mtpt, mtlen);
+#else
+#ifdef __GNUC__
+ #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
+#endif
+ *mount_flags = 0;
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+ }
+ if (retval)
+ return retval;
+
+#ifdef __linux__ /* This only works on Linux 2.6+ systems */
+ {
+ struct stat st_buf;
+ int fd;
+ if ((stat(device, &st_buf) != 0) ||
+ !S_ISBLK(st_buf.st_mode))
+ return 0;
+ fd = open(device, O_RDONLY|O_EXCL|O_CLOEXEC);
+ if (fd < 0) {
+ if (errno == EBUSY)
+ *mount_flags |= MF_BUSY;
+ } else
+ close(fd);
+ }
+#endif
+
+ return 0;
+}
+
+int is_mounted(const char *file)
+{
+ int retval;
+ int mount_flags = 0;
+
+ retval = check_mount_point(file, &mount_flags, NULL, 0);
+ if (retval)
+ return 0;
+ return mount_flags & MF_MOUNTED;
+}
+
+#ifdef TEST_PROGRAM_ISMOUNTED
+int main(int argc, char **argv)
+{
+ int flags = 0;
+ char devname[PATH_MAX];
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s device\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if (check_mount_point(argv[1], &flags, devname, sizeof(devname)) == 0 &&
+ (flags & MF_MOUNTED)) {
+ if (flags & MF_SWAP)
+ printf("used swap device\n");
+ else
+ printf("mounted on %s\n", devname);
+ return EXIT_SUCCESS;
+ }
+
+ printf("not mounted\n");
+ return EXIT_FAILURE;
+}
+#endif /* DEBUG */
diff --git a/src/utils/lib/langinfo.c b/src/utils/lib/langinfo.c
new file mode 100644
index 0000000..a200085
--- /dev/null
+++ b/src/utils/lib/langinfo.c
@@ -0,0 +1,124 @@
+/*
+ * This is callback solution for systems without nl_langinfo(), this function
+ * returns hardcoded and on locale setting indepndent value.
+ *
+ * See langinfo.h man page for more details.
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ */
+#include "nls.h"
+
+char *langinfo_fallback(nl_item item)
+{
+ switch (item) {
+ case CODESET:
+ return "ISO-8859-1";
+ case THOUSEP:
+ return ",";
+ case D_T_FMT:
+ case ERA_D_T_FMT:
+ return "%a %b %e %H:%M:%S %Y";
+ case D_FMT:
+ case ERA_D_FMT:
+ return "%m/%d/%y";
+ case T_FMT:
+ case ERA_T_FMT:
+ return "%H:%M:%S";
+ case T_FMT_AMPM:
+ return "%I:%M:%S %p";
+ case AM_STR:
+ return "AM";
+ case PM_STR:
+ return "PM";
+ case DAY_1:
+ return "Sunday";
+ case DAY_2:
+ return "Monday";
+ case DAY_3:
+ return "Tuesday";
+ case DAY_4:
+ return "Wednesday";
+ case DAY_5:
+ return "Thursday";
+ case DAY_6:
+ return "Friday";
+ case DAY_7:
+ return "Saturday";
+ case ABDAY_1:
+ return "Sun";
+ case ABDAY_2:
+ return "Mon";
+ case ABDAY_3:
+ return "Tue";
+ case ABDAY_4:
+ return "Wed";
+ case ABDAY_5:
+ return "Thu";
+ case ABDAY_6:
+ return "Fri";
+ case ABDAY_7:
+ return "Sat";
+ case MON_1:
+ return "January";
+ case MON_2:
+ return "February";
+ case MON_3:
+ return "March";
+ case MON_4:
+ return "April";
+ case MON_5:
+ return "May";
+ case MON_6:
+ return "June";
+ case MON_7:
+ return "July";
+ case MON_8:
+ return "August";
+ case MON_9:
+ return "September";
+ case MON_10:
+ return "October";
+ case MON_11:
+ return "November";
+ case MON_12:
+ return "December";
+ case ABMON_1:
+ return "Jan";
+ case ABMON_2:
+ return "Feb";
+ case ABMON_3:
+ return "Mar";
+ case ABMON_4:
+ return "Apr";
+ case ABMON_5:
+ return "May";
+ case ABMON_6:
+ return "Jun";
+ case ABMON_7:
+ return "Jul";
+ case ABMON_8:
+ return "Aug";
+ case ABMON_9:
+ return "Sep";
+ case ABMON_10:
+ return "Oct";
+ case ABMON_11:
+ return "Nov";
+ case ABMON_12:
+ return "Dec";
+ case ALT_DIGITS:
+ return "\0\0\0\0\0\0\0\0\0\0";
+ case CRNCYSTR:
+ return "-";
+ case YESEXPR:
+ return "^[yY]";
+ case NOEXPR:
+ return "^[nN]";
+ default:
+ return "";
+ }
+}
+
diff --git a/src/utils/lib/linux_version.c b/src/utils/lib/linux_version.c
new file mode 100644
index 0000000..137bbe7
--- /dev/null
+++ b/src/utils/lib/linux_version.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <sys/utsname.h>
+
+#include "c.h"
+#include "linux_version.h"
+
+int get_linux_version (void)
+{
+ static int kver = -1;
+ struct utsname uts;
+ int x = 0, y = 0, z = 0;
+ int n;
+
+ if (kver != -1)
+ return kver;
+ if (uname(&uts))
+ return kver = 0;
+
+ n = sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
+ if (n < 1 || n > 3)
+ return kver = 0;
+
+ return kver = KERNEL_VERSION(x, y, z);
+}
+
+#ifdef TEST_PROGRAM_LINUXVERSION
+# include <stdlib.h>
+int main(int argc, char *argv[])
+{
+ int rc = EXIT_FAILURE;
+
+ if (argc == 1) {
+ printf("Linux version: %d\n", get_linux_version());
+ rc = EXIT_SUCCESS;
+
+ } else if (argc == 5) {
+ const char *oper = argv[1];
+
+ int x = atoi(argv[2]),
+ y = atoi(argv[3]),
+ z = atoi(argv[4]);
+ int kver = get_linux_version();
+ int uver = KERNEL_VERSION(x, y, z);
+
+ if (strcmp(oper, "==") == 0)
+ rc = kver == uver;
+ else if (strcmp(oper, "<=") == 0)
+ rc = kver <= uver;
+ else if (strcmp(oper, ">=") == 0)
+ rc = kver >= uver;
+ else
+ errx(EXIT_FAILURE, "unsupported operator");
+
+ if (rc)
+ printf("match\n");
+ else
+ printf("not-match [%d %s %d, x.y.z: %d.%d.%d]\n",
+ kver, oper, uver, x, y, z);
+
+ rc = rc ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ } else
+ fprintf(stderr, "Usage:\n"
+ " %s [<oper> <x> <y> <z>]\n"
+ "supported operators:\n"
+ " ==, <=, >=\n",
+ program_invocation_short_name);
+
+ return rc;
+}
+#endif
diff --git a/src/utils/lib/loopdev.c b/src/utils/lib/loopdev.c
new file mode 100644
index 0000000..be4e486
--- /dev/null
+++ b/src/utils/lib/loopdev.c
@@ -0,0 +1,1914 @@
+
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ *
+ * -- based on mount/losetup.c
+ *
+ * Simple library for work with loop devices.
+ *
+ * - requires kernel 2.6.x
+ * - reads info from /sys/block/loop<N>/loop/<attr> (new kernels)
+ * - reads info by ioctl
+ * - supports *unlimited* number of loop devices
+ * - supports /dev/xloop<N> as well as /dev/xloop/<N>
+ * - minimize overhead (fd, loopinfo, ... are shared for all operations)
+ * - setup (associate device and backing file)
+ * - delete (dis-associate file)
+ * - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported
+ * - extendible
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <inttypes.h>
+#include <dirent.h>
+
+#include "linux_version.h"
+#include "c.h"
+#include "sysfs.h"
+#include "pathnames.h"
+#include "loopdev.h"
+#include "canonicalize.h"
+#include "blkdev.h"
+#include "debug.h"
+
+/*
+ * Debug stuff (based on include/debug.h)
+ */
+static UL_DEBUG_DEFINE_MASK(loopdev);
+UL_DEBUG_DEFINE_MASKNAMES(loopdev) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define XLOOPDEV_DEBUG_INIT (1 << 1)
+#define XLOOPDEV_DEBUG_CXT (1 << 2)
+#define XLOOPDEV_DEBUG_ITER (1 << 3)
+#define XLOOPDEV_DEBUG_SETUP (1 << 4)
+
+#define DBG(m, x) __UL_DBG(loopdev, XLOOPDEV_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(loopdev, XLOOPDEV_DEBUG_, m, x)
+
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(loopdev)
+#include "debugobj.h"
+
+static void loopdev_init_debug(void)
+{
+ if (loopdev_debug_mask)
+ return;
+ __UL_INIT_DEBUG_FROM_ENV(loopdev, XLOOPDEV_DEBUG_, 0, XLOOPDEV_DEBUG);
+}
+
+/*
+ * see loopcxt_init()
+ */
+#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL))
+#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \
+ && !loopcxt_ioctl_enabled(_lc)
+
+/*
+ * @lc: context
+ * @device: device name, absolute device path or NULL to reset the current setting
+ *
+ * Sets device, absolute paths (e.g. "/dev/xloop<N>") are unchanged, device
+ * names ("xloop<N>") are converted to the path (/dev/xloop<N> or to
+ * /dev/xloop/<N>)
+ *
+ * This sets the device name, but does not check if the device exists!
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
+{
+ if (!lc)
+ return -EINVAL;
+
+ if (lc->fd >= 0) {
+ close(lc->fd);
+ DBG(CXT, ul_debugobj(lc, "closing old open fd"));
+ }
+ lc->fd = -1;
+ lc->mode = 0;
+ lc->blocksize = 0;
+ lc->has_info = 0;
+ lc->info_failed = 0;
+ *lc->device = '\0';
+ memset(&lc->info, 0, sizeof(lc->info));
+
+ /* set new */
+ if (device) {
+ if (*device != '/') {
+ const char *dir = _PATH_DEV;
+
+ /* compose device name for /dev/xloop<n> or /dev/xloop/<n> */
+ if (lc->flags & LOOPDEV_FL_DEVSUBDIR) {
+ if (strlen(device) <= 5)
+ return -1;
+ device += 5;
+ dir = _PATH_DEV_LOOP "/"; /* _PATH_DEV uses tailing slash */
+ }
+ snprintf(lc->device, sizeof(lc->device), "%s%s",
+ dir, device);
+ } else
+ xstrncpy(lc->device, device, sizeof(lc->device));
+
+ DBG(CXT, ul_debugobj(lc, "%s name assigned", device));
+ }
+
+ ul_unref_path(lc->sysfs);
+ lc->sysfs = NULL;
+ return 0;
+}
+
+int loopcxt_has_device(struct loopdev_cxt *lc)
+{
+ return lc && *lc->device;
+}
+
+/*
+ * @lc: context
+ * @flags: LOOPDEV_FL_* flags
+ *
+ * Initialize loop handler.
+ *
+ * We have two sets of the flags:
+ *
+ * * LOOPDEV_FL_* flags control loopcxt_* API behavior
+ *
+ * * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls
+ *
+ * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2)
+ * syscall to open loop device. By default is the device open read-only.
+ *
+ * The exception is loopcxt_setup_device(), where the device is open read-write
+ * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()).
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int loopcxt_init(struct loopdev_cxt *lc, int flags)
+{
+ int rc;
+ struct stat st;
+ struct loopdev_cxt dummy = UL_LOOPDEVCXT_EMPTY;
+
+ if (!lc)
+ return -EINVAL;
+
+ loopdev_init_debug();
+ DBG(CXT, ul_debugobj(lc, "initialize context"));
+
+ memcpy(lc, &dummy, sizeof(dummy));
+ lc->flags = flags;
+
+ rc = loopcxt_set_device(lc, NULL);
+ if (rc)
+ return rc;
+
+ if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) {
+ lc->flags |= LOOPDEV_FL_NOSYSFS;
+ lc->flags &= ~LOOPDEV_FL_NOIOCTL;
+ DBG(CXT, ul_debugobj(lc, "init: disable /sys usage"));
+ }
+
+ if (!(lc->flags & LOOPDEV_FL_NOSYSFS) &&
+ get_linux_version() >= KERNEL_VERSION(2,6,37)) {
+ /*
+ * Use only sysfs for basic information about loop devices
+ */
+ lc->flags |= LOOPDEV_FL_NOIOCTL;
+ DBG(CXT, ul_debugobj(lc, "init: ignore ioctls"));
+ }
+
+ if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) {
+ lc->flags |= LOOPDEV_FL_CONTROL;
+ DBG(CXT, ul_debugobj(lc, "init: xloop-control detected "));
+ }
+
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Deinitialize loop context
+ */
+void loopcxt_deinit(struct loopdev_cxt *lc)
+{
+ int errsv = errno;
+
+ if (!lc)
+ return;
+
+ DBG(CXT, ul_debugobj(lc, "de-initialize"));
+
+ free(lc->filename);
+ lc->filename = NULL;
+
+ ignore_result( loopcxt_set_device(lc, NULL) );
+ loopcxt_deinit_iterator(lc);
+
+ errno = errsv;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns newly allocated device path.
+ */
+char *loopcxt_strdup_device(struct loopdev_cxt *lc)
+{
+ if (!lc || !*lc->device)
+ return NULL;
+ return strdup(lc->device);
+}
+
+/*
+ * @lc: context
+ *
+ * Returns pointer device name in the @lc struct.
+ */
+const char *loopcxt_get_device(struct loopdev_cxt *lc)
+{
+ return lc && *lc->device ? lc->device : NULL;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns pointer to the sysfs context (see lib/sysfs.c)
+ */
+static struct path_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc)
+{
+ if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS))
+ return NULL;
+
+ if (!lc->sysfs) {
+ dev_t devno = sysfs_devname_to_devno(lc->device);
+ if (!devno) {
+ DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno"));
+ return NULL;
+ }
+
+ lc->sysfs = ul_new_sysfs_path(devno, NULL, NULL);
+ if (!lc->sysfs)
+ DBG(CXT, ul_debugobj(lc, "sysfs: init failed"));
+ }
+
+ return lc->sysfs;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: file descriptor to the open loop device or <0 on error. The mode
+ * depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is
+ * read-only.
+ */
+int loopcxt_get_fd(struct loopdev_cxt *lc)
+{
+ if (!lc || !*lc->device)
+ return -EINVAL;
+
+ if (lc->fd < 0) {
+ lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
+ lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
+ DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device,
+ lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro"));
+ }
+ return lc->fd;
+}
+
+int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode)
+{
+ if (!lc)
+ return -EINVAL;
+
+ lc->fd = fd;
+ lc->mode = mode;
+ return 0;
+}
+
+/*
+ * @lc: context
+ * @flags: LOOPITER_FL_* flags
+ *
+ * Iterator can be used to scan list of the free or used loop devices.
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags)
+{
+ struct loopdev_iter *iter;
+ struct stat st;
+
+ if (!lc)
+ return -EINVAL;
+
+
+ iter = &lc->iter;
+ DBG(ITER, ul_debugobj(iter, "initialize"));
+
+ /* always zeroize
+ */
+ memset(iter, 0, sizeof(*iter));
+ iter->ncur = -1;
+ iter->flags = flags;
+ iter->default_check = 1;
+
+ if (!lc->extra_check) {
+ /*
+ * Check for /dev/xloop/<N> subdirectory
+ */
+ if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) &&
+ stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode))
+ lc->flags |= LOOPDEV_FL_DEVSUBDIR;
+
+ lc->extra_check = 1;
+ }
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter;
+
+ if (!lc)
+ return -EINVAL;
+
+ iter = &lc->iter;
+ DBG(ITER, ul_debugobj(iter, "de-initialize"));
+
+ free(iter->minors);
+ if (iter->proc)
+ fclose(iter->proc);
+ if (iter->sysblock)
+ closedir(iter->sysblock);
+
+ memset(iter, 0, sizeof(*iter));
+ return 0;
+}
+
+/*
+ * Same as loopcxt_set_device, but also checks if the device is
+ * associated with any file.
+ *
+ * Returns: <0 on error, 0 on success, 1 device does not match with
+ * LOOPITER_FL_{USED,FREE} flags.
+ */
+static int loopiter_set_device(struct loopdev_cxt *lc, const char *device)
+{
+ int rc = loopcxt_set_device(lc, device);
+ int used;
+
+ if (rc)
+ return rc;
+
+ if (!(lc->iter.flags & LOOPITER_FL_USED) &&
+ !(lc->iter.flags & LOOPITER_FL_FREE))
+ return 0; /* caller does not care about device status */
+
+ if (!is_loopdev(lc->device)) {
+ DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device));
+ return -errno;
+ }
+
+ DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device));
+
+ used = loopcxt_get_offset(lc, NULL) == 0;
+
+ if ((lc->iter.flags & LOOPITER_FL_USED) && used)
+ return 0;
+
+ if ((lc->iter.flags & LOOPITER_FL_FREE) && !used)
+ return 0;
+
+ DBG(ITER, ul_debugobj(&lc->iter, "failed to use %s device", lc->device));
+
+ ignore_result( loopcxt_set_device(lc, NULL) );
+ return 1;
+}
+
+static int cmpnum(const void *p1, const void *p2)
+{
+ return (((* (const int *) p1) > (* (const int *) p2)) -
+ ((* (const int *) p1) < (* (const int *) p2)));
+}
+
+/*
+ * The classic scandir() is more expensive and less portable.
+ * We needn't full loop device names -- loop numbers (loop<N>)
+ * are enough.
+ */
+static int loop_scandir(const char *dirname, int **ary, int hasprefix)
+{
+ DIR *dir;
+ struct dirent *d;
+ unsigned int n, count = 0, arylen = 0;
+
+ if (!dirname || !ary)
+ return 0;
+
+ DBG(ITER, ul_debug("scan dir: %s", dirname));
+
+ dir = opendir(dirname);
+ if (!dir)
+ return 0;
+ free(*ary);
+ *ary = NULL;
+
+ while((d = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN &&
+ d->d_type != DT_LNK)
+ continue;
+#endif
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ if (hasprefix) {
+ /* /dev/xloop<N> */
+ if (sscanf(d->d_name, "xloop%u", &n) != 1)
+ continue;
+ } else {
+ /* /dev/xloop/<N> */
+ char *end = NULL;
+
+ errno = 0;
+ n = strtol(d->d_name, &end, 10);
+ if (d->d_name == end || (end && *end) || errno)
+ continue;
+ }
+ if (n < LOOPDEV_DEFAULT_NNODES)
+ continue; /* ignore xloop<0..7> */
+
+ if (count + 1 > arylen) {
+ int *tmp;
+
+ arylen += 1;
+
+ tmp = realloc(*ary, arylen * sizeof(int));
+ if (!tmp) {
+ free(*ary);
+ *ary = NULL;
+ closedir(dir);
+ return -1;
+ }
+ *ary = tmp;
+ }
+ if (*ary)
+ (*ary)[count++] = n;
+ }
+ if (count && *ary)
+ qsort(*ary, count, sizeof(int), cmpnum);
+
+ closedir(dir);
+ return count;
+}
+
+/*
+ * Set the next *used* loop device according to /proc/partitions.
+ *
+ * Loop devices smaller than 512 bytes are invisible for this function.
+ */
+static int loopcxt_next_from_proc(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter = &lc->iter;
+ char buf[BUFSIZ];
+
+ DBG(ITER, ul_debugobj(iter, "scan /proc/partitions"));
+
+ if (!iter->proc)
+ iter->proc = fopen(_PATH_PROC_PARTITIONS, "r" UL_CLOEXECSTR);
+ if (!iter->proc)
+ return 1;
+
+ while (fgets(buf, sizeof(buf), iter->proc)) {
+ unsigned int m;
+ char name[128 + 1];
+
+
+ if (sscanf(buf, " %u %*s %*s %128[^\n ]",
+ &m, name) != 2 || m != LOOPDEV_MAJOR)
+ continue;
+
+ DBG(ITER, ul_debugobj(iter, "checking %s", name));
+
+ if (loopiter_set_device(lc, name) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Set the next *used* loop device according to
+ * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required).
+ *
+ * This is preferred method.
+ */
+static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter = &lc->iter;
+ struct dirent *d;
+ int fd;
+
+ DBG(ITER, ul_debugobj(iter, "scanning /sys/block"));
+
+ if (!iter->sysblock)
+ iter->sysblock = opendir(_PATH_SYS_BLOCK);
+
+ if (!iter->sysblock)
+ return 1;
+
+ fd = dirfd(iter->sysblock);
+
+ while ((d = readdir(iter->sysblock))) {
+ char name[NAME_MAX + 18 + 1];
+ struct stat st;
+
+ DBG(ITER, ul_debugobj(iter, "check %s", d->d_name));
+
+ if (strcmp(d->d_name, ".") == 0
+ || strcmp(d->d_name, "..") == 0
+ || strncmp(d->d_name, "xloop", 4) != 0)
+ continue;
+
+ snprintf(name, sizeof(name), "%s/xloop/backing_file", d->d_name);
+ if (fstatat(fd, name, &st, 0) != 0)
+ continue;
+
+ if (loopiter_set_device(lc, d->d_name) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * @lc: context, has to initialized by loopcxt_init_iterator()
+ *
+ * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details
+ * about the current loop device are available by
+ * loopcxt_get_{fd,backing_file,device,offset, ...} functions.
+ */
+int loopcxt_next(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter;
+
+ if (!lc)
+ return -EINVAL;
+
+
+ iter = &lc->iter;
+ if (iter->done)
+ return 1;
+
+ DBG(ITER, ul_debugobj(iter, "next"));
+
+ /* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
+ */
+ if (iter->flags & LOOPITER_FL_USED) {
+ int rc;
+
+ if (loopcxt_sysfs_available(lc))
+ rc = loopcxt_next_from_sysfs(lc);
+ else
+ rc = loopcxt_next_from_proc(lc);
+ if (rc == 0)
+ return 0;
+ goto done;
+ }
+
+ /* B) Classic way, try first eight loop devices (default number
+ * of loop devices). This is enough for 99% of all cases.
+ */
+ if (iter->default_check) {
+ DBG(ITER, ul_debugobj(iter, "next: default check"));
+ for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES;
+ iter->ncur++) {
+ char name[16];
+ snprintf(name, sizeof(name), "xloop%d", iter->ncur);
+
+ if (loopiter_set_device(lc, name) == 0)
+ return 0;
+ }
+ iter->default_check = 0;
+ }
+
+ /* C) the worst possibility, scan whole /dev or /dev/xloop/<N>
+ */
+ if (!iter->minors) {
+ DBG(ITER, ul_debugobj(iter, "next: scanning /dev"));
+ iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ?
+ loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) :
+ loop_scandir(_PATH_DEV, &iter->minors, 1);
+ iter->ncur = -1;
+ }
+ for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) {
+ char name[16];
+ snprintf(name, sizeof(name), "xloop%d", iter->minors[iter->ncur]);
+
+ if (loopiter_set_device(lc, name) == 0)
+ return 0;
+ }
+done:
+ loopcxt_deinit_iterator(lc);
+ return 1;
+}
+
+/*
+ * @device: path to device
+ */
+int is_loopdev(const char *device)
+{
+ struct stat st;
+
+ if (device && stat(device, &st) == 0 &&
+ S_ISBLK(st.st_mode) &&
+ major(st.st_rdev) == LOOPDEV_MAJOR)
+ return 1;
+
+ errno = ENODEV;
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns result from LOOP_GET_STAT64 ioctl or NULL on error.
+ */
+struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc)
+{
+ int fd;
+
+ if (!lc || lc->info_failed) {
+ errno = EINVAL;
+ return NULL;
+ }
+ errno = 0;
+ if (lc->has_info)
+ return &lc->info;
+
+ fd = loopcxt_get_fd(lc);
+ if (fd < 0)
+ return NULL;
+
+ if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) {
+ lc->has_info = 1;
+ lc->info_failed = 0;
+ DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK"));
+ return &lc->info;
+ }
+
+ lc->info_failed = 1;
+ DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED"));
+
+ return NULL;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns (allocated) string with path to the file associated
+ * with the current loop device.
+ */
+char *loopcxt_get_backing_file(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ char *res = NULL;
+
+ if (sysfs)
+ /*
+ * This is always preferred, the loop_info64
+ * has too small buffer for the filename.
+ */
+ ul_path_read_string(sysfs, &res, "xloop/backing_file");
+
+ if (!res && loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+
+ if (lo) {
+ lo->lo_file_name[LO_NAME_SIZE - 2] = '*';
+ lo->lo_file_name[LO_NAME_SIZE - 1] = '\0';
+ res = strdup((char *) lo->lo_file_name);
+ }
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_backing_file [%s]", res));
+ return res;
+}
+
+/*
+ * @lc: context
+ * @offset: returns offset number for the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = -EINVAL;
+
+ if (sysfs)
+ rc = ul_path_read_u64(sysfs, offset, "xloop/offset");
+
+ if (rc && loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo) {
+ if (offset)
+ *offset = lo->lo_offset;
+ rc = 0;
+ } else
+ rc = -errno;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_offset [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @blocksize: returns logical blocksize for the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_blocksize(struct loopdev_cxt *lc, uint64_t *blocksize)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = -EINVAL;
+
+ if (sysfs)
+ rc = ul_path_read_u64(sysfs, blocksize, "queue/logical_block_size");
+
+ /* Fallback based on BLKSSZGET ioctl */
+ if (rc) {
+ int fd = loopcxt_get_fd(lc);
+ int sz = 0;
+
+ if (fd < 0)
+ return -EINVAL;
+ rc = blkdev_get_sector_size(fd, &sz);
+ if (rc)
+ return rc;
+
+ *blocksize = sz;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_blocksize [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @sizelimit: returns size limit for the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = -EINVAL;
+
+ if (sysfs)
+ rc = ul_path_read_u64(sysfs, size, "xloop/sizelimit");
+
+ if (rc && loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo) {
+ if (size)
+ *size = lo->lo_sizelimit;
+ rc = 0;
+ } else
+ rc = -errno;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "get_sizelimit [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @devno: returns encryption type
+ *
+ * Cryptoloop is DEPRECATED!
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type)
+{
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ int rc;
+
+ /* not provided by sysfs */
+ if (lo) {
+ if (type)
+ *type = lo->lo_encrypt_type;
+ rc = 0;
+ } else
+ rc = -errno;
+
+ DBG(CXT, ul_debugobj(lc, "get_encrypt_type [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @file_fmt_type_str: file format type string.
+ * @file_fmt_type: returns file format type from the given file format string.
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int parse_file_fmt_type(const char *file_fmt_type_str, uint32_t *file_fmt_type)
+{
+ int rc = 0;
+
+ if (!strcmp(file_fmt_type_str, "RAW"))
+ *file_fmt_type = LO_FILE_FMT_RAW;
+ else if (!strcmp(file_fmt_type_str, "QCOW"))
+ *file_fmt_type = LO_FILE_FMT_QCOW;
+ else if (!strcmp(file_fmt_type_str, "VDI"))
+ *file_fmt_type = LO_FILE_FMT_VDI;
+ else if (!strcmp(file_fmt_type_str, "VMDK"))
+ *file_fmt_type = LO_FILE_FMT_VMDK;
+ else
+ rc = -EINVAL;
+
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @file_fmt_type: returns file format type of the given device
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_file_fmt_type(struct loopdev_cxt *lc, uint32_t* file_fmt_type)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ int rc = 0;
+
+ if (sysfs) {
+ /* check if file_fmt_type is accessible and supported by the kernel module */
+ char* file_fmt_str = NULL;
+ if (ul_path_read_string(sysfs, &file_fmt_str, "xloop/file_fmt_type") == 0)
+ rc = parse_file_fmt_type(file_fmt_str, file_fmt_type);
+ } else
+ rc = -errno;
+
+ if (rc != 0 && loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo)
+ *file_fmt_type = lo->lo_file_fmt_type;
+ }
+
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns (allocated) string with file format type of the current loop device.
+ */
+char *loopcxt_get_file_fmt_type_string(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+ char *res = NULL;
+
+ if (sysfs)
+ ul_path_read_string(sysfs, &res, "xloop/file_fmt_type");
+
+ DBG(CXT, ul_debugobj(lc, "xloopcxt_get_file_fmt_type_string [%s]", res));
+ return res;
+}
+
+/*
+ * @lc: context
+ * @devno: returns crypt name
+ *
+ * Cryptoloop is DEPRECATED!
+ *
+ * Returns: <0 on error, 0 on success
+ */
+const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc)
+{
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+
+ if (lo)
+ return (char *) lo->lo_crypt_name;
+
+ DBG(CXT, ul_debugobj(lc, "get_crypt_name failed"));
+ return NULL;
+}
+
+/*
+ * @lc: context
+ * @devno: returns backing file devno
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno)
+{
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ int rc;
+
+ if (lo) {
+ if (devno)
+ *devno = lo->lo_device;
+ rc = 0;
+ } else
+ rc = -errno;
+
+ DBG(CXT, ul_debugobj(lc, "get_backing_devno [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
+ * @ino: returns backing file inode
+ *
+ * Returns: <0 on error, 0 on success
+ */
+int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino)
+{
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ int rc;
+
+ if (lo) {
+ if (ino)
+ *ino = lo->lo_inode;
+ rc = 0;
+ } else
+ rc = -errno;
+
+ DBG(CXT, ul_debugobj(lc, "get_backing_inode [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * Check if the kernel supports partitioned loop devices.
+ *
+ * Notes:
+ * - kernels < 3.2 support partitioned loop devices and PT scanning
+ * only if max_part= module parameter is non-zero
+ *
+ * - kernels >= 3.2 always support partitioned loop devices
+ *
+ * - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls
+ *
+ * - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the
+ * LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled
+ * by default.
+ *
+ * See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98.
+ */
+int loopmod_supports_partscan(void)
+{
+ int rc, ret = 0;
+ FILE *f;
+
+ if (get_linux_version() >= KERNEL_VERSION(3,2,0))
+ return 1;
+
+ f = fopen("/sys/module/loop/parameters/max_part", "r" UL_CLOEXECSTR);
+ if (!f)
+ return 0;
+ rc = fscanf(f, "%d", &ret);
+ fclose(f);
+ return rc == 1 ? ret : 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: 1 if the partscan flags is set *or* (for old kernels) partitions
+ * scanning is enabled for all loop devices.
+ */
+int loopcxt_is_partscan(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+
+ if (sysfs) {
+ /* kernel >= 3.2 */
+ int fl;
+ if (ul_path_read_s32(sysfs, &fl, "xloop/partscan") == 0)
+ return fl;
+ }
+
+ /* old kernels (including kernels without loopN/loop/<flags> directory */
+ return loopmod_supports_partscan();
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: 1 if the autoclear flags is set.
+ */
+int loopcxt_is_autoclear(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+
+ if (sysfs) {
+ int fl;
+ if (ul_path_read_s32(sysfs, &fl, "xloop/autoclear") == 0)
+ return fl;
+ }
+
+ if (loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo)
+ return lo->lo_flags & LO_FLAGS_AUTOCLEAR;
+ }
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: 1 if the readonly flags is set.
+ */
+int loopcxt_is_readonly(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+
+ if (sysfs) {
+ int fl;
+ if (ul_path_read_s32(sysfs, &fl, "ro") == 0)
+ return fl;
+ }
+
+ if (loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo)
+ return lo->lo_flags & LO_FLAGS_READ_ONLY;
+ }
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Returns: 1 if the dio flags is set.
+ */
+int loopcxt_is_dio(struct loopdev_cxt *lc)
+{
+ struct path_cxt *sysfs = loopcxt_get_sysfs(lc);
+
+ if (sysfs) {
+ int fl;
+ if (ul_path_read_s32(sysfs, &fl, "xloop/dio") == 0)
+ return fl;
+ }
+ if (loopcxt_ioctl_enabled(lc)) {
+ struct loop_info64 *lo = loopcxt_get_info(lc);
+ if (lo)
+ return lo->lo_flags & LO_FLAGS_DIRECT_IO;
+ }
+ return 0;
+}
+
+/*
+ * @lc: context
+ * @st: backing file stat or NULL
+ * @backing_file: filename
+ * @offset: offset (use LOOPDEV_FL_OFFSET if specified)
+ * @sizelimit: size limit (use LOOPDEV_FL_SIZELIMIT if specified)
+ * @flags: LOOPDEV_FL_{OFFSET,SIZELIMIT}
+ *
+ * Returns 1 if the current @lc loopdev is associated with the given backing
+ * file. Note that the preferred way is to use devno and inode number rather
+ * than filename. The @backing_file filename is poor solution usable in case
+ * that you don't have rights to call stat().
+ *
+ * LOOPDEV_FL_SIZELIMIT requires LOOPDEV_FL_OFFSET being set as well.
+ *
+ * Don't forget that old kernels provide very restricted (in size) backing
+ * filename by LOOP_GET_STAT64 ioctl only.
+ */
+int loopcxt_is_used(struct loopdev_cxt *lc,
+ struct stat *st,
+ const char *backing_file,
+ uint64_t offset,
+ uint64_t sizelimit,
+ int flags)
+{
+ ino_t ino = 0;
+ dev_t dev = 0;
+
+ if (!lc)
+ return 0;
+
+ DBG(CXT, ul_debugobj(lc, "checking %s vs. %s",
+ loopcxt_get_device(lc),
+ backing_file));
+
+ if (st && loopcxt_get_backing_inode(lc, &ino) == 0 &&
+ loopcxt_get_backing_devno(lc, &dev) == 0) {
+
+ if (ino == st->st_ino && dev == st->st_dev)
+ goto found;
+
+ /* don't use filename if we have devno and inode */
+ return 0;
+ }
+
+ /* poor man's solution */
+ if (backing_file) {
+ char *name = loopcxt_get_backing_file(lc);
+ int rc = name && strcmp(name, backing_file) == 0;
+
+ free(name);
+ if (rc)
+ goto found;
+ }
+
+ return 0;
+found:
+ if (flags & LOOPDEV_FL_OFFSET) {
+ uint64_t off = 0;
+
+ int rc = loopcxt_get_offset(lc, &off) == 0 && off == offset;
+
+ if (rc && flags & LOOPDEV_FL_SIZELIMIT) {
+ uint64_t sz = 0;
+
+ return loopcxt_get_sizelimit(lc, &sz) == 0 && sz == sizelimit;
+ }
+ return rc;
+ }
+ return 1;
+}
+
+/*
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ */
+int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset)
+{
+ if (!lc)
+ return -EINVAL;
+ lc->info.lo_offset = offset;
+
+ DBG(CXT, ul_debugobj(lc, "set offset=%jd", offset));
+ return 0;
+}
+
+/*
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ */
+int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit)
+{
+ if (!lc)
+ return -EINVAL;
+ lc->info.lo_sizelimit = sizelimit;
+
+ DBG(CXT, ul_debugobj(lc, "set sizelimit=%jd", sizelimit));
+ return 0;
+}
+
+/*
+ * The blocksize will be used by loopcxt_set_device(). For already exiting
+ * devices use loopcxt_ioctl_blocksize().
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ */
+int loopcxt_set_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
+{
+ if (!lc)
+ return -EINVAL;
+ lc->blocksize = blocksize;
+
+ DBG(CXT, ul_debugobj(lc, "set blocksize=%jd", blocksize));
+ return 0;
+}
+
+/*
+ * @lc: context
+ * @file_fmt_type: kernel LO_FILE_FMT_{RAW,QCOW,VDI,VMDK} flags
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int loopcxt_set_file_fmt_type(struct loopdev_cxt *lc, uint32_t file_fmt_type) {
+ if (!lc)
+ return -EINVAL;
+ lc->info.lo_file_fmt_type = file_fmt_type;
+
+ DBG(CXT, ul_debugobj(lc, "set file_fmt_type=%u", (unsigned) file_fmt_type));
+ return 0;
+}
+
+/*
+ * @lc: context
+ * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags)
+{
+ if (!lc)
+ return -EINVAL;
+ lc->info.lo_flags = flags;
+
+ DBG(CXT, ul_debugobj(lc, "set flags=%u", (unsigned) flags));
+ return 0;
+}
+
+/*
+ * @lc: context
+ * @filename: backing file path (the path will be canonicalized)
+ *
+ * The setting is removed by loopcxt_set_device() loopcxt_next()!
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename)
+{
+ if (!lc)
+ return -EINVAL;
+
+ lc->filename = canonicalize_path(filename);
+ if (!lc->filename)
+ return -errno;
+
+ xstrncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE);
+
+ DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->info.lo_file_name));
+ return 0;
+}
+
+/*
+ * In kernels prior to v3.9, if the offset or sizelimit options
+ * are used, the block device's size won't be synced automatically.
+ * blockdev --getsize64 and filesystems will use the backing
+ * file size until the block device has been re-opened or the
+ * LOOP_SET_CAPACITY ioctl is called to sync the sizes.
+ *
+ * Since mount -oloop uses the LO_FLAGS_AUTOCLEAR option and passes
+ * the open file descriptor to the mount system call, we need to use
+ * the ioctl. Calling losetup directly doesn't have this problem since
+ * it closes the device when it exits and whatever consumes the device
+ * next will re-open it, causing the resync.
+ */
+static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
+{
+ uint64_t size, expected_size;
+ int dev_fd;
+ struct stat st;
+
+ if (!lc->info.lo_offset && !lc->info.lo_sizelimit)
+ return 0;
+
+ if (fstat(file_fd, &st)) {
+ DBG(CXT, ul_debugobj(lc, "failed to fstat backing file"));
+ return -errno;
+ }
+ if (S_ISBLK(st.st_mode)) {
+ if (blkdev_get_size(file_fd,
+ (unsigned long long *) &expected_size)) {
+ DBG(CXT, ul_debugobj(lc, "failed to determine device size"));
+ return -errno;
+ }
+ } else
+ expected_size = st.st_size;
+
+ if (expected_size == 0 || expected_size <= lc->info.lo_offset) {
+ DBG(CXT, ul_debugobj(lc, "failed to determine expected size"));
+ return 0; /* ignore this error */
+ }
+
+ if (lc->info.lo_offset > 0)
+ expected_size -= lc->info.lo_offset;
+
+ if (lc->info.lo_sizelimit > 0 && lc->info.lo_sizelimit < expected_size)
+ expected_size = lc->info.lo_sizelimit;
+
+ dev_fd = loopcxt_get_fd(lc);
+ if (dev_fd < 0) {
+ DBG(CXT, ul_debugobj(lc, "failed to get loop FD"));
+ return -errno;
+ }
+
+ if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) {
+ DBG(CXT, ul_debugobj(lc, "failed to determine loopdev size"));
+ return -errno;
+ }
+
+ /* It's block device, so, align to 512-byte sectors */
+ if (expected_size % 512) {
+ DBG(CXT, ul_debugobj(lc, "expected size misaligned to 512-byte sectors"));
+ expected_size = (expected_size >> 9) << 9;
+ }
+
+ if (expected_size != size) {
+ DBG(CXT, ul_debugobj(lc, "warning: loopdev and expected "
+ "size mismatch (%ju/%ju)",
+ size, expected_size));
+
+ if (loopcxt_ioctl_capacity(lc)) {
+ /* ioctl not available */
+ if (errno == ENOTTY || errno == EINVAL)
+ errno = ERANGE;
+ return -errno;
+ }
+
+ if (blkdev_get_size(dev_fd, (unsigned long long *) &size))
+ return -errno;
+
+ if (expected_size != size) {
+ errno = ERANGE;
+ DBG(CXT, ul_debugobj(lc, "failed to set loopdev size, "
+ "size: %ju, expected: %ju",
+ size, expected_size));
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * @lc: context
+ *
+ * Associate the current device (see loopcxt_{set,get}_device()) with
+ * a file (see loopcxt_set_backing_file()).
+ *
+ * The device is initialized read-write by default. If you want read-only
+ * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_*
+ * flags are ignored and modified according to LO_FLAGS_*.
+ *
+ * If the device is already open by loopcxt_get_fd() then this setup device
+ * function will re-open the device to fix read/write mode.
+ *
+ * The device is also initialized read-only if the backing file is not
+ * possible to open read-write (e.g. read-only FS).
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int loopcxt_setup_device(struct loopdev_cxt *lc)
+{
+ int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0, err, again;
+ int errsv = 0;
+
+ if (!lc || !*lc->device || !lc->filename)
+ return -EINVAL;
+
+ DBG(SETUP, ul_debugobj(lc, "device setup requested"));
+
+ /*
+ * Open backing file and device
+ */
+ if (lc->info.lo_flags & LO_FLAGS_READ_ONLY)
+ mode = O_RDONLY;
+
+ if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) {
+ if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
+ file_fd = open(lc->filename, mode = O_RDONLY);
+
+ if (file_fd < 0) {
+ DBG(SETUP, ul_debugobj(lc, "open backing file failed: %m"));
+ return -errno;
+ }
+ }
+ DBG(SETUP, ul_debugobj(lc, "backing file open: OK"));
+
+ if (lc->fd != -1 && lc->mode != mode) {
+ DBG(SETUP, ul_debugobj(lc, "closing already open device (mode mismatch)"));
+ close(lc->fd);
+ lc->fd = -1;
+ lc->mode = 0;
+ }
+
+ if (mode == O_RDONLY) {
+ lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */
+ lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */
+ } else {
+ lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */
+ lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY;
+ lc->flags &= ~LOOPDEV_FL_RDONLY;
+ }
+
+ do {
+ errno = 0;
+ dev_fd = loopcxt_get_fd(lc);
+ if (dev_fd >= 0 || lc->control_ok == 0)
+ break;
+ if (errno != EACCES && errno != ENOENT)
+ break;
+ /* We have permissions to open /dev/xloop-control, but open
+ * /dev/xloopN failed with EACCES, it's probably because udevd
+ * does not applied chown yet. Let's wait a moment. */
+ xusleep(25000);
+ } while (cnt++ < 16);
+
+ if (dev_fd < 0) {
+ rc = -errno;
+ goto err;
+ }
+
+ DBG(SETUP, ul_debugobj(lc, "device open: OK"));
+
+ /*
+ * Set FD
+ */
+ if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
+ rc = -errno;
+ errsv = errno;
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m"));
+ goto err;
+ }
+
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK"));
+
+ if (lc->blocksize > 0
+ && (rc = loopcxt_ioctl_blocksize(lc, lc->blocksize)) < 0) {
+ errsv = -rc;
+ goto err;
+ }
+
+ do {
+ err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info);
+ again = err && errno == EAGAIN;
+ if (again)
+ xusleep(250000);
+ } while (again);
+ if (err) {
+ rc = -errno;
+ errsv = errno;
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
+ goto err;
+ }
+
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK"));
+
+ if ((rc = loopcxt_check_size(lc, file_fd)))
+ goto err;
+
+ close(file_fd);
+
+ memset(&lc->info, 0, sizeof(lc->info));
+ lc->has_info = 0;
+ lc->info_failed = 0;
+
+ DBG(SETUP, ul_debugobj(lc, "success [rc=0]"));
+ return 0;
+err:
+ if (file_fd >= 0)
+ close(file_fd);
+ if (dev_fd >= 0 && rc != -EBUSY)
+ ioctl(dev_fd, LOOP_CLR_FD, 0);
+ if (errsv)
+ errno = errsv;
+
+ DBG(SETUP, ul_debugobj(lc, "failed [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * @lc: context
+ *
+ * Update status of the current device (see loopcxt_{set,get}_device()).
+ *
+ * Note that once initialized, kernel accepts only selected changes:
+ * LO_FLAGS_AUTOCLEAR and LO_FLAGS_PARTSCAN
+ * For more see linux/drivers/block/loop.c:loop_set_status()
+ *
+ * Returns: <0 on error, 0 on success.
+ */
+int loopcxt_ioctl_status(struct loopdev_cxt *lc)
+{
+ int dev_fd, rc = -1, err, again;
+
+ errno = 0;
+ dev_fd = loopcxt_get_fd(lc);
+
+ if (dev_fd < 0) {
+ rc = -errno;
+ return rc;
+ }
+ DBG(SETUP, ul_debugobj(lc, "device open: OK"));
+
+ do {
+ err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info);
+ again = err && errno == EAGAIN;
+ if (again)
+ xusleep(250000);
+ } while (again);
+ if (err) {
+ rc = -errno;
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
+ return rc;
+ }
+
+ DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK"));
+ return 0;
+}
+
+int loopcxt_ioctl_capacity(struct loopdev_cxt *lc)
+{
+ int fd = loopcxt_get_fd(lc);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Kernels prior to v2.6.30 don't support this ioctl */
+ if (ioctl(fd, LOOP_SET_CAPACITY, 0) < 0) {
+ int rc = -errno;
+ DBG(CXT, ul_debugobj(lc, "LOOP_SET_CAPACITY failed: %m"));
+ return rc;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "capacity set"));
+ return 0;
+}
+
+int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio)
+{
+ int fd = loopcxt_get_fd(lc);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Kernels prior to v4.4 don't support this ioctl */
+ if (ioctl(fd, LOOP_SET_DIRECT_IO, use_dio) < 0) {
+ int rc = -errno;
+ DBG(CXT, ul_debugobj(lc, "LOOP_SET_DIRECT_IO failed: %m"));
+ return rc;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "direct io set"));
+ return 0;
+}
+
+/*
+ * Kernel uses "unsigned long" as ioctl arg, but we use u64 for all sizes to
+ * keep loopdev internal API simple.
+ */
+int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize)
+{
+ int fd = loopcxt_get_fd(lc);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ /* Kernels prior to v4.14 don't support this ioctl */
+ if (ioctl(fd, LOOP_SET_BLOCK_SIZE, (unsigned long) blocksize) < 0) {
+ int rc = -errno;
+ DBG(CXT, ul_debugobj(lc, "LOOP_SET_BLOCK_SIZE failed: %m"));
+ return rc;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "logical block size set"));
+ return 0;
+}
+
+int loopcxt_delete_device(struct loopdev_cxt *lc)
+{
+ int fd = loopcxt_get_fd(lc);
+
+ if (fd < 0)
+ return -EINVAL;
+
+ if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+ DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m"));
+ return -errno;
+ }
+
+ DBG(CXT, ul_debugobj(lc, "device removed"));
+ return 0;
+}
+
+int loopcxt_add_device(struct loopdev_cxt *lc)
+{
+ int rc = -EINVAL;
+ int ctl, nr = -1;
+ const char *p, *dev = loopcxt_get_device(lc);
+
+ if (!dev)
+ goto done;
+
+ if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
+ rc = -ENOSYS;
+ goto done;
+ }
+
+ p = strrchr(dev, '/');
+ if (!p || (sscanf(p, "/xloop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1)
+ || nr < 0)
+ goto done;
+
+ ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
+ if (ctl >= 0) {
+ DBG(CXT, ul_debugobj(lc, "add_device %d", nr));
+ rc = ioctl(ctl, LOOP_CTL_ADD, nr);
+ close(ctl);
+ }
+ lc->control_ok = rc >= 0 ? 1 : 0;
+done:
+ DBG(CXT, ul_debugobj(lc, "add_device done [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older
+ * kernels we have to check all loop devices to found unused one.
+ *
+ * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484.
+ */
+int loopcxt_find_unused(struct loopdev_cxt *lc)
+{
+ int rc = -1;
+
+ DBG(CXT, ul_debugobj(lc, "find_unused requested"));
+
+ if (lc->flags & LOOPDEV_FL_CONTROL) {
+ int ctl;
+
+ DBG(CXT, ul_debugobj(lc, "using xloop-control"));
+
+ ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
+ if (ctl >= 0)
+ rc = ioctl(ctl, LOOP_CTL_GET_FREE);
+ if (rc >= 0) {
+ char name[16];
+ snprintf(name, sizeof(name), "xloop%d", rc);
+
+ rc = loopiter_set_device(lc, name);
+ }
+ lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0;
+ if (ctl >= 0)
+ close(ctl);
+ DBG(CXT, ul_debugobj(lc, "find_unused by xloop-control [rc=%d]", rc));
+ }
+
+ if (rc < 0) {
+ DBG(CXT, ul_debugobj(lc, "using loop scan"));
+ rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE);
+ if (rc)
+ return rc;
+
+ rc = loopcxt_next(lc);
+ loopcxt_deinit_iterator(lc);
+ DBG(CXT, ul_debugobj(lc, "find_unused by scan [rc=%d]", rc));
+ }
+ return rc;
+}
+
+
+
+/*
+ * Return: TRUE/FALSE
+ */
+int loopdev_is_autoclear(const char *device)
+{
+ struct loopdev_cxt lc;
+ int rc;
+
+ if (!device)
+ return 0;
+
+ rc = loopcxt_init(&lc, 0);
+ if (!rc)
+ rc = loopcxt_set_device(&lc, device);
+ if (!rc)
+ rc = loopcxt_is_autoclear(&lc);
+
+ loopcxt_deinit(&lc);
+ return rc;
+}
+
+char *loopdev_get_backing_file(const char *device)
+{
+ struct loopdev_cxt lc;
+ char *res = NULL;
+
+ if (!device)
+ return NULL;
+ if (loopcxt_init(&lc, 0))
+ return NULL;
+ if (loopcxt_set_device(&lc, device) == 0)
+ res = loopcxt_get_backing_file(&lc);
+
+ loopcxt_deinit(&lc);
+ return res;
+}
+
+/*
+ * Returns: TRUE/FALSE
+ */
+int loopdev_is_used(const char *device, const char *filename,
+ uint64_t offset, uint64_t sizelimit, int flags)
+{
+ struct loopdev_cxt lc;
+ struct stat st;
+ int rc = 0;
+
+ if (!device || !filename)
+ return 0;
+
+ rc = loopcxt_init(&lc, 0);
+ if (!rc)
+ rc = loopcxt_set_device(&lc, device);
+ if (rc)
+ return rc;
+
+ rc = !stat(filename, &st);
+ rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, sizelimit, flags);
+
+ loopcxt_deinit(&lc);
+ return rc;
+}
+
+int loopdev_delete(const char *device)
+{
+ struct loopdev_cxt lc;
+ int rc;
+
+ if (!device)
+ return -EINVAL;
+
+ rc = loopcxt_init(&lc, 0);
+ if (!rc)
+ rc = loopcxt_set_device(&lc, device);
+ if (!rc)
+ rc = loopcxt_delete_device(&lc);
+ loopcxt_deinit(&lc);
+ return rc;
+}
+
+/*
+ * Returns: 0 = success, < 0 error, 1 not found
+ */
+int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename,
+ uint64_t offset, uint64_t sizelimit, int flags)
+{
+ int rc, hasst;
+ struct stat st;
+
+ if (!filename)
+ return -EINVAL;
+
+ hasst = !stat(filename, &st);
+
+ rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
+ if (rc)
+ return rc;
+
+ while ((rc = loopcxt_next(lc)) == 0) {
+
+ if (loopcxt_is_used(lc, hasst ? &st : NULL,
+ filename, offset, sizelimit, flags))
+ break;
+ }
+
+ loopcxt_deinit_iterator(lc);
+ return rc;
+}
+
+/*
+ * Returns: 0 = not found, < 0 error, 1 found, 2 found full size and offset match
+ */
+int loopcxt_find_overlap(struct loopdev_cxt *lc, const char *filename,
+ uint64_t offset, uint64_t sizelimit)
+{
+ int rc, hasst;
+ struct stat st;
+
+ if (!filename)
+ return -EINVAL;
+
+ DBG(CXT, ul_debugobj(lc, "find_overlap requested"));
+ hasst = !stat(filename, &st);
+
+ rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
+ if (rc)
+ return rc;
+
+ while ((rc = loopcxt_next(lc)) == 0) {
+ uint64_t lc_sizelimit, lc_offset;
+
+ rc = loopcxt_is_used(lc, hasst ? &st : NULL,
+ filename, offset, sizelimit, 0);
+ if (!rc)
+ continue; /* unused */
+ if (rc < 0)
+ break; /* error */
+
+ DBG(CXT, ul_debugobj(lc, "found %s backed by %s",
+ loopcxt_get_device(lc), filename));
+
+ rc = loopcxt_get_offset(lc, &lc_offset);
+ if (rc) {
+ DBG(CXT, ul_debugobj(lc, "failed to get offset for device %s",
+ loopcxt_get_device(lc)));
+ break;
+ }
+ rc = loopcxt_get_sizelimit(lc, &lc_sizelimit);
+ if (rc) {
+ DBG(CXT, ul_debugobj(lc, "failed to get sizelimit for device %s",
+ loopcxt_get_device(lc)));
+ break;
+ }
+
+ /* full match */
+ if (lc_sizelimit == sizelimit && lc_offset == offset) {
+ DBG(CXT, ul_debugobj(lc, "overlapping loop device %s (full match)",
+ loopcxt_get_device(lc)));
+ rc = 2;
+ goto found;
+ }
+
+ /* overlap */
+ if (lc_sizelimit != 0 && offset >= lc_offset + lc_sizelimit)
+ continue;
+ if (sizelimit != 0 && offset + sizelimit <= lc_offset)
+ continue;
+
+ DBG(CXT, ul_debugobj(lc, "overlapping loop device %s",
+ loopcxt_get_device(lc)));
+ rc = 1;
+ goto found;
+ }
+
+ if (rc == 1)
+ rc = 0; /* not found */
+found:
+ loopcxt_deinit_iterator(lc);
+ DBG(CXT, ul_debugobj(lc, "find_overlap done [rc=%d]", rc));
+ return rc;
+}
+
+/*
+ * Returns allocated string with device name
+ */
+char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, uint64_t sizelimit, int flags)
+{
+ struct loopdev_cxt lc;
+ char *res = NULL;
+
+ if (!filename)
+ return NULL;
+
+ if (loopcxt_init(&lc, 0))
+ return NULL;
+ if (loopcxt_find_by_backing_file(&lc, filename, offset, sizelimit, flags) == 0)
+ res = loopcxt_strdup_device(&lc);
+ loopcxt_deinit(&lc);
+
+ return res;
+}
+
+/*
+ * Returns number of loop devices associated with @file, if only one loop
+ * device is associated with the given @filename and @loopdev is not NULL then
+ * @loopdev returns name of the device.
+ */
+int loopdev_count_by_backing_file(const char *filename, char **loopdev)
+{
+ struct loopdev_cxt lc;
+ int count = 0, rc;
+
+ if (!filename)
+ return -1;
+
+ rc = loopcxt_init(&lc, 0);
+ if (rc)
+ return rc;
+ if (loopcxt_init_iterator(&lc, LOOPITER_FL_USED))
+ return -1;
+
+ while(loopcxt_next(&lc) == 0) {
+ char *backing = loopcxt_get_backing_file(&lc);
+
+ if (!backing || strcmp(backing, filename) != 0) {
+ free(backing);
+ continue;
+ }
+
+ free(backing);
+ if (loopdev && count == 0)
+ *loopdev = loopcxt_strdup_device(&lc);
+ count++;
+ }
+
+ loopcxt_deinit(&lc);
+
+ if (loopdev && count > 1) {
+ free(*loopdev);
+ *loopdev = NULL;
+ }
+ return count;
+}
+
diff --git a/src/utils/lib/mangle.c b/src/utils/lib/mangle.c
new file mode 100644
index 0000000..1a3b89a
--- /dev/null
+++ b/src/utils/lib/mangle.c
@@ -0,0 +1,169 @@
+/*
+ * Functions for \oct encoding used in mtab/fstab/swaps/etc.
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "mangle.h"
+#include "c.h"
+
+#define isoctal(a) (((a) & ~7) == '0')
+
+#define from_hex(c) (isdigit(c) ? c - '0' : tolower(c) - 'a' + 10)
+
+#define is_unwanted_char(x) (strchr(" \t\n\\", (unsigned int) x) != NULL)
+
+
+char *mangle(const char *s)
+{
+ char *ss, *sp;
+
+ if (!s)
+ return NULL;
+
+ ss = sp = malloc(4 * strlen(s) + 1);
+ if (!sp)
+ return NULL;
+ while(1) {
+ if (!*s) {
+ *sp = '\0';
+ break;
+ }
+ if (is_unwanted_char(*s)) {
+ *sp++ = '\\';
+ *sp++ = '0' + ((*s & 0300) >> 6);
+ *sp++ = '0' + ((*s & 070) >> 3);
+ *sp++ = '0' + (*s & 07);
+ } else
+ *sp++ = *s;
+ s++;
+ }
+ return ss;
+}
+
+
+void unmangle_to_buffer(const char *s, char *buf, size_t len)
+{
+ size_t sz = 0;
+
+ if (!s)
+ return;
+
+ while(*s && sz < len - 1) {
+ if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) &&
+ isoctal(s[2]) && isoctal(s[3])) {
+
+ *buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
+ s += 4;
+ sz += 4;
+ } else {
+ *buf++ = *s++;
+ sz++;
+ }
+ }
+ *buf = '\0';
+}
+
+size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len)
+{
+ size_t sz = 0;
+ const char *buf0 = buf;
+
+ if (!s)
+ return 0;
+
+ while(*s && sz < len - 1) {
+ if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' &&
+ isxdigit(s[2]) && isxdigit(s[3])) {
+
+ *buf++ = from_hex(s[2]) << 4 | from_hex(s[3]);
+ s += 4;
+ sz += 4;
+ } else {
+ *buf++ = *s++;
+ sz++;
+ }
+ }
+ *buf = '\0';
+ return buf - buf0 + 1;
+}
+
+static inline const char *skip_nonspaces(const char *s)
+{
+ while (s && *s && !(*s == ' ' || *s == '\t'))
+ s++;
+ return s;
+}
+
+/*
+ * Returns mallocated buffer or NULL in case of error.
+ */
+char *unmangle(const char *s, const char **end)
+{
+ char *buf;
+ const char *e;
+ size_t sz;
+
+ if (!s)
+ return NULL;
+
+ e = skip_nonspaces(s);
+ sz = e - s + 1;
+
+ if (end)
+ *end = e;
+ if (e == s)
+ return NULL; /* empty string */
+
+ buf = malloc(sz);
+ if (!buf)
+ return NULL;
+
+ unmangle_to_buffer(s, buf, sz);
+ return buf;
+}
+
+#ifdef TEST_PROGRAM_MANGLE
+#include <errno.h>
+int main(int argc, char *argv[])
+{
+ char *p = NULL;
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s --mangle|unmangle <string>\n",
+ program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+
+ if (!strcmp(argv[1], "--mangle")) {
+ p = mangle(argv[2]);
+ printf("mangled: '%s'\n", p);
+ free(p);
+ }
+
+ else if (!strcmp(argv[1], "--unmangle")) {
+ char *x = unmangle(argv[2], NULL);
+
+ if (x) {
+ printf("unmangled: '%s'\n", x);
+ free(x);
+ }
+
+ x = strdup(argv[2]);
+ if (x) {
+ unmangle_to_buffer(x, x, strlen(x) + 1);
+
+ printf("self-unmangled: '%s'\n", x);
+ free(x);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_MANGLE */
diff --git a/src/utils/lib/match.c b/src/utils/lib/match.c
new file mode 100644
index 0000000..a286a19
--- /dev/null
+++ b/src/utils/lib/match.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <string.h>
+
+#include "match.h"
+
+/*
+ * match_fstype:
+ * @type: filesystem type
+ * @pattern: filesystem name or comma delimited list of names
+ *
+ * The @pattern list of filesystem can be prefixed with a global
+ * "no" prefix to invert matching of the whole list. The "no" could
+ * also be used for individual items in the @pattern list. So,
+ * "nofoo,bar" has the same meaning as "nofoo,nobar".
+ */
+int match_fstype(const char *type, const char *pattern)
+{
+ int no = 0; /* negated types list */
+ int len;
+ const char *p;
+
+ if (!pattern && !type)
+ return 1;
+ if (!pattern)
+ return 0;
+
+ if (!strncmp(pattern, "no", 2)) {
+ no = 1;
+ pattern += 2;
+ }
+
+ /* Does type occur in types, separated by commas? */
+ len = strlen(type);
+ p = pattern;
+ while(1) {
+ if (!strncmp(p, "no", 2) && !strncasecmp(p+2, type, len) &&
+ (p[len+2] == 0 || p[len+2] == ','))
+ return 0;
+ if (strncasecmp(p, type, len) == 0 && (p[len] == 0 || p[len] == ','))
+ return !no;
+ p = strchr(p,',');
+ if (!p)
+ break;
+ p++;
+ }
+ return no;
+}
diff --git a/src/utils/lib/mbsalign.c b/src/utils/lib/mbsalign.c
new file mode 100644
index 0000000..e251202
--- /dev/null
+++ b/src/utils/lib/mbsalign.c
@@ -0,0 +1,627 @@
+/* Align/Truncate a string in a given screen width
+ Copyright (C) 2009-2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Written by Pádraig Brady. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "c.h"
+#include "mbsalign.h"
+#include "strutils.h"
+#include "widechar.h"
+
+/*
+ * Counts number of cells in multibyte string. All control and
+ * non-printable chars are ignored.
+ *
+ * Returns: number of cells.
+ */
+size_t mbs_nwidth(const char *buf, size_t bufsz)
+{
+ const char *p = buf, *last = buf;
+ size_t width = 0;
+
+#ifdef HAVE_WIDECHAR
+ mbstate_t st;
+ memset(&st, 0, sizeof(st));
+#endif
+ if (p && *p && bufsz)
+ last = p + (bufsz - 1);
+
+ while (p && *p && p <= last) {
+ if (iscntrl((unsigned char) *p)) {
+ p++;
+
+ /* try detect "\e[x;ym" and skip on success */
+ if (*p && *p == '[') {
+ const char *e = p;
+ while (*e && e < last && *e != 'm')
+ e++;
+ if (*e == 'm')
+ p = e + 1;
+ }
+ continue;
+ }
+#ifdef HAVE_WIDECHAR
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+ if (len == 0)
+ break;
+ if (len > 0 && iswprint(wc)) {
+ int x = wcwidth(wc);
+ if (x > 0)
+ width += x;
+ } else if (len == (size_t) -1 || len == (size_t) -2)
+ len = 1;
+ p += len;
+#else
+ if (isprint((unsigned char) *p))
+ width++;
+ p++;
+#endif
+ }
+
+ return width;
+}
+
+size_t mbs_width(const char *s)
+{
+ if (!s || !*s)
+ return 0;
+ return mbs_nwidth(s, strlen(s));
+}
+
+/*
+ * Counts number of cells in multibyte string. For all control and
+ * non-printable chars is the result width enlarged to store \x?? hex
+ * sequence. See mbs_safe_encode().
+ *
+ * Returns: number of cells, @sz returns number of bytes.
+ */
+size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz)
+{
+ const char *p = buf, *last = buf;
+ size_t width = 0, bytes = 0;
+
+#ifdef HAVE_WIDECHAR
+ mbstate_t st;
+ memset(&st, 0, sizeof(st));
+#endif
+ if (p && *p && bufsz)
+ last = p + (bufsz - 1);
+
+ while (p && *p && p <= last) {
+ if ((p < last && *p == '\\' && *(p + 1) == 'x')
+ || iscntrl((unsigned char) *p)) {
+ width += 4, bytes += 4; /* *p encoded to \x?? */
+ p++;
+ }
+#ifdef HAVE_WIDECHAR
+ else {
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+ if (len == 0)
+ break;
+
+ if (len == (size_t) -1 || len == (size_t) -2) {
+ len = 1;
+ if (isprint((unsigned char) *p))
+ width += 1, bytes += 1;
+ else
+ width += 4, bytes += 4;
+
+ } else if (!iswprint(wc)) {
+ width += len * 4; /* hex encode whole sequence */
+ bytes += len * 4;
+ } else {
+ width += wcwidth(wc); /* number of cells */
+ bytes += len; /* number of bytes */
+ }
+ p += len;
+ }
+#else
+ else if (!isprint((unsigned char) *p)) {
+ width += 4, bytes += 4; /* *p encoded to \x?? */
+ p++;
+ } else {
+ width++, bytes++;
+ p++;
+ }
+#endif
+ }
+
+ if (sz)
+ *sz = bytes;
+ return width;
+}
+
+size_t mbs_safe_width(const char *s)
+{
+ if (!s || !*s)
+ return 0;
+ return mbs_safe_nwidth(s, strlen(s), NULL);
+}
+
+/*
+ * Copy @s to @buf and replace control and non-printable chars with
+ * \x?? hex sequence. The @width returns number of cells. The @safechars
+ * are not encoded.
+ *
+ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
+ * bytes.
+ */
+char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf, const char *safechars)
+{
+ const char *p = s;
+ char *r;
+ size_t sz = s ? strlen(s) : 0;
+
+#ifdef HAVE_WIDECHAR
+ mbstate_t st;
+ memset(&st, 0, sizeof(st));
+#endif
+ if (!sz || !buf)
+ return NULL;
+
+ r = buf;
+ *width = 0;
+
+ while (p && *p) {
+ if (safechars && strchr(safechars, *p)) {
+ *r++ = *p++;
+ continue;
+ }
+
+ if ((*p == '\\' && *(p + 1) == 'x')
+ || iscntrl((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ p++;
+ }
+#ifdef HAVE_WIDECHAR
+ else {
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+
+ if (len == 0)
+ break; /* end of string */
+
+ if (len == (size_t) -1 || len == (size_t) -2) {
+ len = 1;
+ /*
+ * Not valid multibyte sequence -- maybe it's
+ * printable char according to the current locales.
+ */
+ if (!isprint((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ } else {
+ (*width)++;
+ *r++ = *p;
+ }
+ } else if (!iswprint(wc)) {
+ size_t i;
+ for (i = 0; i < len; i++) {
+ sprintf(r, "\\x%02x", (unsigned char) p[i]);
+ r += 4;
+ *width += 4;
+ }
+ } else {
+ memcpy(r, p, len);
+ r += len;
+ *width += wcwidth(wc);
+ }
+ p += len;
+ }
+#else
+ else if (!isprint((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ p++;
+ r += 4;
+ *width += 4;
+ } else {
+ *r++ = *p++;
+ (*width)++;
+ }
+#endif
+ }
+
+ *r = '\0';
+ return buf;
+}
+
+/*
+ * Copy @s to @buf and replace broken sequences to \x?? hex sequence. The
+ * @width returns number of cells. The @safechars are not encoded.
+ *
+ * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s)))
+ * bytes.
+ */
+char *mbs_invalid_encode_to_buffer(const char *s, size_t *width, char *buf)
+{
+ const char *p = s;
+ char *r;
+ size_t sz = s ? strlen(s) : 0;
+
+#ifdef HAVE_WIDECHAR
+ mbstate_t st;
+ memset(&st, 0, sizeof(st));
+#endif
+ if (!sz || !buf)
+ return NULL;
+
+ r = buf;
+ *width = 0;
+
+ while (p && *p) {
+#ifdef HAVE_WIDECHAR
+ wchar_t wc;
+ size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st);
+#else
+ size_t len = 1;
+#endif
+
+ if (len == 0)
+ break; /* end of string */
+
+ if (len == (size_t) -1 || len == (size_t) -2) {
+ len = 1;
+ /*
+ * Not valid multibyte sequence -- maybe it's
+ * printable char according to the current locales.
+ */
+ if (!isprint((unsigned char) *p)) {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ } else {
+ (*width)++;
+ *r++ = *p;
+ }
+ } else if (*p == '\\' && *(p + 1) == 'x') {
+ sprintf(r, "\\x%02x", (unsigned char) *p);
+ r += 4;
+ *width += 4;
+ } else {
+ memcpy(r, p, len);
+ r += len;
+ *width += wcwidth(wc);
+ }
+ p += len;
+ }
+
+ *r = '\0';
+ return buf;
+}
+
+size_t mbs_safe_encode_size(size_t bytes)
+{
+ return (bytes * 4) + 1;
+}
+
+/*
+ * Returns allocated string where all control and non-printable chars are
+ * replaced with \x?? hex sequence.
+ */
+char *mbs_safe_encode(const char *s, size_t *width)
+{
+ size_t sz = s ? strlen(s) : 0;
+ char *buf, *ret = NULL;
+
+ if (!sz)
+ return NULL;
+ buf = malloc(mbs_safe_encode_size(sz));
+ if (buf)
+ ret = mbs_safe_encode_to_buffer(s, width, buf, NULL);
+ if (!ret)
+ free(buf);
+ return ret;
+}
+
+/*
+ * Returns allocated string where all broken widechars chars are
+ * replaced with \x?? hex sequence.
+ */
+char *mbs_invalid_encode(const char *s, size_t *width)
+{
+ size_t sz = s ? strlen(s) : 0;
+ char *buf, *ret = NULL;
+
+ if (!sz)
+ return NULL;
+ buf = malloc(mbs_safe_encode_size(sz));
+ if (buf)
+ ret = mbs_invalid_encode_to_buffer(s, width, buf);
+ if (!ret)
+ free(buf);
+ return ret;
+}
+
+#ifdef HAVE_WIDECHAR
+
+static bool
+wc_ensure_printable (wchar_t *wchars)
+{
+ bool replaced = false;
+ wchar_t *wc = wchars;
+ while (*wc)
+ {
+ if (!iswprint ((wint_t) *wc))
+ {
+ *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */
+ replaced = true;
+ }
+ wc++;
+ }
+ return replaced;
+}
+
+/* Truncate wchar string to width cells.
+ * Returns number of cells used. */
+
+static size_t
+wc_truncate (wchar_t *wc, size_t width)
+{
+ size_t cells = 0;
+ int next_cells = 0;
+
+ while (*wc)
+ {
+ next_cells = wcwidth (*wc);
+ if (next_cells == -1) /* non printable */
+ {
+ *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */
+ next_cells = 1;
+ }
+ if (cells + next_cells > width)
+ break;
+
+ cells += next_cells;
+ wc++;
+ }
+ *wc = L'\0';
+ return cells;
+}
+
+static int
+rpl_wcswidth (const wchar_t *s, size_t n)
+{
+ int ret = 0;
+
+ while (n-- > 0 && *s != L'\0')
+ {
+ int nwidth = wcwidth (*s++);
+ if (nwidth == -1) /* non printable */
+ return -1;
+ if (ret > (INT_MAX - nwidth)) /* overflow */
+ return -1;
+ ret += nwidth;
+ }
+
+ return ret;
+}
+#endif /* HAVE_WIDECHAR */
+
+/* Truncate multi-byte string to @width and returns number of
+ * bytes of the new string @str, and in @width returns number
+ * of cells.
+ */
+size_t
+mbs_truncate(char *str, size_t *width)
+{
+ ssize_t bytes = strlen(str);
+#ifdef HAVE_WIDECHAR
+ ssize_t sz = mbstowcs(NULL, str, 0);
+ wchar_t *wcs = NULL;
+
+ if (sz == (ssize_t) -1)
+ goto done;
+
+ wcs = calloc(1, (sz + 1) * sizeof(wchar_t));
+ if (!wcs)
+ goto done;
+
+ if (!mbstowcs(wcs, str, sz))
+ goto done;
+ *width = wc_truncate(wcs, *width);
+ bytes = wcstombs(str, wcs, bytes);
+done:
+ free(wcs);
+#else
+ if (bytes >= 0 && *width < (size_t) bytes)
+ bytes = *width;
+#endif
+ if (bytes >= 0)
+ str[bytes] = '\0';
+ return bytes;
+}
+
+/* Write N_SPACES space characters to DEST while ensuring
+ nothing is written beyond DEST_END. A terminating NUL
+ is always added to DEST.
+ A pointer to the terminating NUL is returned. */
+
+static char*
+mbs_align_pad (char *dest, const char* dest_end, size_t n_spaces, int padchar)
+{
+ for (/* nothing */; n_spaces && (dest < dest_end); n_spaces--)
+ *dest++ = padchar;
+ *dest = '\0';
+ return dest;
+}
+
+size_t
+mbsalign (const char *src, char *dest, size_t dest_size,
+ size_t *width, mbs_align_t align, int flags)
+{
+ return mbsalign_with_padding(src, dest, dest_size, width, align, flags, ' ');
+}
+
+/* Align a string, SRC, in a field of *WIDTH columns, handling multi-byte
+ characters; write the result into the DEST_SIZE-byte buffer, DEST.
+ ALIGNMENT specifies whether to left- or right-justify or to center.
+ If SRC requires more than *WIDTH columns, truncate it to fit.
+ When centering, the number of trailing spaces may be one less than the
+ number of leading spaces. The FLAGS parameter is unused at present.
+ Return the length in bytes required for the final result, not counting
+ the trailing NUL. A return value of DEST_SIZE or larger means there
+ wasn't enough space. DEST will be NUL terminated in any case.
+ Return (size_t) -1 upon error (invalid multi-byte sequence in SRC,
+ or malloc failure), unless MBA_UNIBYTE_FALLBACK is specified.
+ Update *WIDTH to indicate how many columns were used before padding. */
+
+size_t
+mbsalign_with_padding (const char *src, char *dest, size_t dest_size,
+ size_t *width, mbs_align_t align,
+#ifdef HAVE_WIDECHAR
+ int flags,
+#else
+ int flags __attribute__((__unused__)),
+#endif
+ int padchar)
+{
+ size_t ret = -1;
+ size_t src_size = strlen (src) + 1;
+ char *newstr = NULL;
+ wchar_t *str_wc = NULL;
+ const char *str_to_print = src;
+ size_t n_cols = src_size - 1;
+ size_t n_used_bytes = n_cols; /* Not including NUL */
+ size_t n_spaces = 0, space_left;
+
+#ifdef HAVE_WIDECHAR
+ bool conversion = false;
+ bool wc_enabled = false;
+
+ /* In multi-byte locales convert to wide characters
+ to allow easy truncation. Also determine number
+ of screen columns used. */
+ if (MB_CUR_MAX > 1)
+ {
+ size_t src_chars = mbstowcs (NULL, src, 0);
+ if (src_chars == (size_t) -1)
+ {
+ if (flags & MBA_UNIBYTE_FALLBACK)
+ goto mbsalign_unibyte;
+ else
+ goto mbsalign_cleanup;
+ }
+ src_chars += 1; /* make space for NUL */
+ str_wc = malloc (src_chars * sizeof (wchar_t));
+ if (str_wc == NULL)
+ {
+ if (flags & MBA_UNIBYTE_FALLBACK)
+ goto mbsalign_unibyte;
+ else
+ goto mbsalign_cleanup;
+ }
+ if (mbstowcs (str_wc, src, src_chars) != 0)
+ {
+ str_wc[src_chars - 1] = L'\0';
+ wc_enabled = true;
+ conversion = wc_ensure_printable (str_wc);
+ n_cols = rpl_wcswidth (str_wc, src_chars);
+ }
+ }
+
+ /* If we transformed or need to truncate the source string
+ then create a modified copy of it. */
+ if (wc_enabled && (conversion || (n_cols > *width)))
+ {
+ if (conversion)
+ {
+ /* May have increased the size by converting
+ \t to \uFFFD for example. */
+ src_size = wcstombs(NULL, str_wc, 0) + 1;
+ }
+ newstr = malloc (src_size);
+ if (newstr == NULL)
+ {
+ if (flags & MBA_UNIBYTE_FALLBACK)
+ goto mbsalign_unibyte;
+ else
+ goto mbsalign_cleanup;
+ }
+ str_to_print = newstr;
+ n_cols = wc_truncate (str_wc, *width);
+ n_used_bytes = wcstombs (newstr, str_wc, src_size);
+ }
+
+mbsalign_unibyte:
+#endif
+
+ if (n_cols > *width) /* Unibyte truncation required. */
+ {
+ n_cols = *width;
+ n_used_bytes = n_cols;
+ }
+
+ if (*width > n_cols) /* Padding required. */
+ n_spaces = *width - n_cols;
+
+ /* indicate to caller how many cells needed (not including padding). */
+ *width = n_cols;
+
+ /* indicate to caller how many bytes needed (not including NUL). */
+ ret = n_used_bytes + (n_spaces * 1);
+
+ /* Write as much NUL terminated output to DEST as possible. */
+ if (dest_size != 0)
+ {
+ char *dest_end = dest + dest_size - 1;
+ size_t start_spaces;
+ size_t end_spaces;
+
+ switch (align)
+ {
+ case MBS_ALIGN_CENTER:
+ start_spaces = n_spaces / 2 + n_spaces % 2;
+ end_spaces = n_spaces / 2;
+ break;
+ case MBS_ALIGN_LEFT:
+ start_spaces = 0;
+ end_spaces = n_spaces;
+ break;
+ case MBS_ALIGN_RIGHT:
+ start_spaces = n_spaces;
+ end_spaces = 0;
+ break;
+ default:
+ abort();
+ }
+
+ dest = mbs_align_pad (dest, dest_end, start_spaces, padchar);
+ space_left = dest_end - dest;
+ dest = mempcpy (dest, str_to_print, min (n_used_bytes, space_left));
+ mbs_align_pad (dest, dest_end, end_spaces, padchar);
+ }
+#ifdef HAVE_WIDECHAR
+mbsalign_cleanup:
+#endif
+ free (str_wc);
+ free (newstr);
+
+ return ret;
+}
diff --git a/src/utils/lib/mbsedit.c b/src/utils/lib/mbsedit.c
new file mode 100644
index 0000000..8ce5901
--- /dev/null
+++ b/src/utils/lib/mbsedit.c
@@ -0,0 +1,225 @@
+/*
+ * Very simple multibyte buffer editor. Allows to maintaine the current
+ * position in the string, add and remove chars on the current position.
+ *
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Copyright (C) 2017 Karel Zak <kzak@redhat.com>
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "mbsalign.h"
+#include "mbsedit.h"
+
+struct mbs_editor *mbs_new_edit(char *buf, size_t bufsz, size_t ncells)
+{
+ struct mbs_editor *edit = calloc(1, sizeof(*edit));
+
+ if (edit) {
+ edit->buf = buf;
+ edit->max_bytes = bufsz;
+ edit->max_cells = ncells;
+ edit->cur_cells = mbs_safe_width(buf);
+ edit->cur_bytes = strlen(buf);
+ }
+ return edit;
+}
+
+char *mbs_free_edit(struct mbs_editor *edit)
+{
+ char *ret = edit ? edit->buf : NULL;
+
+ free(edit);
+ return ret;
+}
+
+static size_t mbs_next(const char *str, size_t *ncells)
+{
+#ifdef HAVE_WIDECHAR
+ wchar_t wc;
+ size_t n = 0;
+
+ if (!str || !*str)
+ return 0;
+
+ n = mbrtowc(&wc, str, MB_CUR_MAX, NULL);
+ *ncells = wcwidth(wc);
+ return n;
+#else
+ if (!str || !*str)
+ return 0;
+ *ncells = 1;
+ return 1;
+#endif
+}
+
+static size_t mbs_prev(const char *start, const char *end, size_t *ncells)
+{
+#ifdef HAVE_WIDECHAR
+ wchar_t wc = 0;
+ const char *p, *prev;
+ size_t n = 0;
+
+ if (!start || !end || start == end || !*start)
+ return 0;
+
+ prev = p = start;
+ while (p < end) {
+ n = mbrtowc(&wc, p, MB_CUR_MAX, NULL);
+ prev = p;
+
+ if (n == (size_t) -1 || n == (size_t) -2)
+ p++;
+ else
+ p += n;
+ }
+
+ if (prev == end)
+ return 0;
+ *ncells = wcwidth(wc);
+ return n;
+#else
+ if (!start || !end || start == end || !*start)
+ return 0;
+ *ncells = 1;
+ return 1;
+#endif
+}
+
+int mbs_edit_goto(struct mbs_editor *edit, int where)
+{
+ switch (where) {
+ case MBS_EDIT_LEFT:
+ if (edit->cursor == 0)
+ return 1;
+ else {
+ size_t n, cells;
+ n = mbs_prev(edit->buf, edit->buf + edit->cursor, &cells);
+ if (n) {
+ edit->cursor -= n;
+ edit->cursor_cells -= cells;
+ }
+ }
+ break;
+ case MBS_EDIT_RIGHT:
+ if (edit->cursor_cells >= edit->cur_cells)
+ return 1;
+ else {
+ size_t n, cells;
+ n = mbs_next(edit->buf + edit->cursor, &cells);
+ if (n) {
+ edit->cursor += n;
+ edit->cursor_cells += cells;
+ }
+ }
+ break;
+ case MBS_EDIT_HOME:
+ edit->cursor = 0;
+ edit->cursor_cells = 0;
+ break;
+ case MBS_EDIT_END:
+ edit->cursor = edit->cur_bytes;
+ edit->cursor_cells = edit->cur_cells;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Remove next MB from @str, returns number of removed bytes */
+static size_t remove_next(char *str, size_t *ncells)
+{
+ /* all in bytes! */
+ size_t bytes, move_bytes, n;
+
+ n = mbs_next(str, ncells);
+ bytes = strlen(str);
+ move_bytes = bytes - n;
+
+ memmove(str, str + n, move_bytes);
+ str[bytes - n] = '\0';
+ return n;
+}
+
+static size_t mbs_insert(char *str, wint_t c, size_t *ncells)
+{
+ /* all in bytes! */
+ size_t n = 1, bytes;
+ char *in;
+
+#ifdef HAVE_WIDECHAR
+ wchar_t wc = (wchar_t) c;
+ char in_buf[MB_CUR_MAX];
+
+ n = wctomb(in_buf, wc);
+ if (n == (size_t) -1)
+ return n;
+ *ncells = wcwidth(wc);
+ in = in_buf;
+#else
+ *ncells = 1;
+ in = (char *) &c;
+#endif
+ bytes = strlen(str);
+
+ memmove(str + n, str, bytes);
+ memcpy(str, in, n);
+ str[bytes + n] = '\0';
+ return n;
+}
+
+static int mbs_edit_remove(struct mbs_editor *edit)
+{
+ size_t n, ncells;
+
+ if (edit->cur_cells == 0 || edit->cursor >= edit->cur_bytes)
+ return 1;
+
+ n = remove_next(edit->buf + edit->cursor, &ncells);
+ if (n == (size_t)-1)
+ return 1;
+
+ edit->cur_bytes -= n;
+ edit->cur_cells = mbs_safe_width(edit->buf);
+ return 0;
+}
+
+int mbs_edit_delete(struct mbs_editor *edit)
+{
+ if (edit->cursor >= edit->cur_bytes
+ && mbs_edit_goto(edit, MBS_EDIT_LEFT) == 1)
+ return 1;
+
+ return mbs_edit_remove(edit);
+}
+
+int mbs_edit_backspace(struct mbs_editor *edit)
+{
+ if (mbs_edit_goto(edit, MBS_EDIT_LEFT) == 0)
+ return mbs_edit_remove(edit);
+ return 1;
+}
+
+int mbs_edit_insert(struct mbs_editor *edit, wint_t c)
+{
+ size_t n, ncells;
+
+ if (edit->cur_bytes + MB_CUR_MAX > edit->max_bytes)
+ return 1;
+
+ n = mbs_insert(edit->buf + edit->cursor, c, &ncells);
+ if (n == (size_t)-1)
+ return 1;
+
+ edit->cursor += n;
+ edit->cursor_cells += ncells;
+ edit->cur_bytes += n;
+ edit->cur_cells = mbs_safe_width(edit->buf);
+ return 0;
+}
diff --git a/src/utils/lib/md5.c b/src/utils/lib/md5.c
new file mode 100644
index 0000000..3765ab9
--- /dev/null
+++ b/src/utils/lib/md5.c
@@ -0,0 +1,257 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+
+#include "md5.h"
+
+#if !defined(WORDS_BIGENDIAN)
+# define byteReverse(buf, len) /* Nothing */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32_t t;
+ do {
+ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif /* !ASM_MD5 */
+#endif /* !WORDS_BIGENDIAN */
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void ul_MD5Init(struct UL_MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void ul_MD5Update(struct UL_MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void ul_MD5Final(unsigned char digest[UL_MD5LENGTH], struct UL_MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform.
+ * Use memcpy to avoid aliasing problems. On most systems,
+ * this will be optimized away to the same code.
+ */
+ memcpy(&ctx->in[14 * sizeof(uint32_t)], &ctx->bits[0], 4);
+ memcpy(&ctx->in[15 * sizeof(uint32_t)], &ctx->bits[1], 4);
+
+ ul_MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, UL_MD5LENGTH);
+ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void ul_MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
+
diff --git a/src/utils/lib/monotonic.c b/src/utils/lib/monotonic.c
new file mode 100644
index 0000000..f0aeba6
--- /dev/null
+++ b/src/utils/lib/monotonic.c
@@ -0,0 +1,81 @@
+/*
+ * Please, don't add this file to libcommon because clock_gettime() requires
+ * -lrt on systems with old libc.
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ */
+#include <time.h>
+#include <signal.h>
+#ifdef HAVE_SYSINFO
+#include <sys/sysinfo.h>
+#endif
+#include <sys/time.h>
+
+#include "c.h"
+#include "monotonic.h"
+
+int get_boot_time(struct timeval *boot_time)
+{
+#ifdef CLOCK_BOOTTIME
+ struct timespec hires_uptime;
+ struct timeval lores_uptime;
+#endif
+ struct timeval now;
+#ifdef HAVE_SYSINFO
+ struct sysinfo info;
+#endif
+
+ if (gettimeofday(&now, NULL) != 0)
+ return -errno;
+#ifdef CLOCK_BOOTTIME
+ if (clock_gettime(CLOCK_BOOTTIME, &hires_uptime) == 0) {
+ TIMESPEC_TO_TIMEVAL(&lores_uptime, &hires_uptime);
+ timersub(&now, &lores_uptime, boot_time);
+ return 0;
+ }
+#endif
+#ifdef HAVE_SYSINFO
+ /* fallback */
+ if (sysinfo(&info) != 0)
+ return -errno;
+
+ boot_time->tv_sec = now.tv_sec - info.uptime;
+ boot_time->tv_usec = 0;
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+time_t get_suspended_time(void)
+{
+#if defined(CLOCK_BOOTTIME) && defined(CLOCK_MONOTONIC)
+ struct timespec boot, mono;
+
+ if (clock_gettime(CLOCK_BOOTTIME, &boot) == 0 &&
+ clock_gettime(CLOCK_MONOTONIC, &mono) == 0)
+ return boot.tv_sec - mono.tv_sec;
+#endif
+ return 0;
+}
+
+int gettime_monotonic(struct timeval *tv)
+{
+#ifdef CLOCK_MONOTONIC
+ /* Can slew only by ntp and adjtime */
+ int ret;
+ struct timespec ts;
+
+ /* Linux specific, can't slew */
+ if (!(ret = clock_gettime(UL_CLOCK_MONOTONIC, &ts))) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ return ret;
+#else
+ return gettimeofday(tv, NULL);
+#endif
+}
+
+
diff --git a/src/utils/lib/pager.c b/src/utils/lib/pager.c
new file mode 100644
index 0000000..b3cf6ee
--- /dev/null
+++ b/src/utils/lib/pager.c
@@ -0,0 +1,317 @@
+/*
+ * Based on linux-perf/git scm
+ *
+ * Some modifications and simplifications for util-linux
+ * by Davidlohr Bueso <dave@xxxxxxx> - March 2012.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "c.h"
+#include "xalloc.h"
+#include "nls.h"
+#include "ttyutils.h"
+#include "pager.h"
+
+#define NULL_DEVICE "/dev/null"
+
+static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
+
+struct child_process {
+ const char **argv;
+ pid_t pid;
+ int in;
+ int out;
+ int err;
+
+ int org_err;
+ int org_out;
+ struct sigaction orig_sigint;
+ struct sigaction orig_sighup;
+ struct sigaction orig_sigterm;
+ struct sigaction orig_sigquit;
+ struct sigaction orig_sigpipe;
+
+ unsigned no_stdin:1;
+ void (*preexec_cb)(void);
+};
+static struct child_process pager_process;
+
+static inline void close_pair(int fd[2])
+{
+ close(fd[0]);
+ close(fd[1]);
+}
+
+static int start_command(struct child_process *cmd)
+{
+ int need_in;
+ int fdin[2];
+
+ /*
+ * In case of errors we must keep the promise to close FDs
+ * that have been passed in via ->in and ->out.
+ */
+ need_in = !cmd->no_stdin && cmd->in < 0;
+ if (need_in) {
+ if (pipe(fdin) < 0) {
+ if (cmd->out > 0)
+ close(cmd->out);
+ return -1;
+ }
+ cmd->in = fdin[1];
+ }
+
+ fflush(NULL);
+ cmd->pid = fork();
+ if (!cmd->pid) {
+ if (need_in) {
+ dup2(fdin[0], STDIN_FILENO);
+ close_pair(fdin);
+ } else if (cmd->in > 0) {
+ dup2(cmd->in, STDIN_FILENO);
+ close(cmd->in);
+ }
+
+ cmd->preexec_cb();
+ execvp(cmd->argv[0], (char *const*) cmd->argv);
+ errexec(cmd->argv[0]);
+ }
+
+ if (cmd->pid < 0) {
+ if (need_in)
+ close_pair(fdin);
+ else if (cmd->in)
+ close(cmd->in);
+ return -1;
+ }
+
+ if (need_in)
+ close(fdin[0]);
+ else if (cmd->in)
+ close(cmd->in);
+ return 0;
+}
+
+static int wait_or_whine(pid_t pid)
+{
+ for (;;) {
+ int status, code;
+ pid_t waiting = waitpid(pid, &status, 0);
+
+ if (waiting < 0) {
+ if (errno == EINTR)
+ continue;
+ err(EXIT_FAILURE, _("waitpid failed (%s)"), strerror(errno));
+ }
+ if (waiting != pid)
+ return -1;
+ if (WIFSIGNALED(status))
+ return -1;
+
+ if (!WIFEXITED(status))
+ return -1;
+ code = WEXITSTATUS(status);
+ switch (code) {
+ case 127:
+ return -1;
+ case 0:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+}
+
+static int finish_command(struct child_process *cmd)
+{
+ return wait_or_whine(cmd->pid);
+}
+
+static void pager_preexec(void)
+{
+ /*
+ * Work around bug in "less" by not starting it until we
+ * have real input
+ */
+ fd_set in, ex;
+
+ FD_ZERO(&in);
+ FD_SET(STDIN_FILENO, &in);
+ ex = in;
+
+ select(STDIN_FILENO + 1, &in, NULL, &ex, NULL);
+
+ if (setenv("LESS", "FRSX", 0) != 0)
+ warn(_("failed to set the %s environment variable"), "LESS");
+}
+
+static void wait_for_pager(void)
+{
+ if (pager_process.pid == 0)
+ return;
+
+ fflush(stdout);
+ fflush(stderr);
+ /* signal EOF to pager */
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ finish_command(&pager_process);
+}
+
+static void wait_for_pager_signal(int signo)
+{
+ wait_for_pager();
+ raise(signo);
+}
+
+static int has_command(const char *cmd)
+{
+ const char *path;
+ char *p, *s;
+ int rc = 0;
+
+ if (!cmd)
+ goto done;
+ if (*cmd == '/') {
+ rc = access(cmd, X_OK) == 0;
+ goto done;
+ }
+
+ path = getenv("PATH");
+ if (!path)
+ goto done;
+ p = xstrdup(path);
+ if (!p)
+ goto done;
+
+ for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
+ int fd = open(s, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ continue;
+ rc = faccessat(fd, cmd, X_OK, 0) == 0;
+ close(fd);
+ if (rc)
+ break;
+ }
+ free(p);
+done:
+ /*fprintf(stderr, "has PAGER %s rc=%d\n", cmd, rc);*/
+ return rc;
+}
+
+static void __setup_pager(void)
+{
+ const char *pager = getenv("PAGER");
+ struct sigaction sa;
+
+ if (!isatty(STDOUT_FILENO))
+ return;
+
+ if (!pager)
+ pager = "less";
+ else if (!*pager || !strcmp(pager, "cat"))
+ return;
+
+ if (!has_command(pager))
+ return;
+
+ /* spawn the pager */
+ pager_argv[2] = pager;
+ pager_process.argv = pager_argv;
+ pager_process.in = -1;
+ pager_process.preexec_cb = pager_preexec;
+
+ if (start_command(&pager_process))
+ return;
+
+ /* original process continues, but writes to the pipe */
+ dup2(pager_process.in, STDOUT_FILENO);
+ if (isatty(STDERR_FILENO))
+ dup2(pager_process.in, STDERR_FILENO);
+ close(pager_process.in);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = wait_for_pager_signal;
+
+ /* this makes sure that the parent terminates after the pager */
+ sigaction(SIGINT, &sa, &pager_process.orig_sigint);
+ sigaction(SIGHUP, &sa, &pager_process.orig_sighup);
+ sigaction(SIGTERM, &sa, &pager_process.orig_sigterm);
+ sigaction(SIGQUIT, &sa, &pager_process.orig_sigquit);
+ sigaction(SIGPIPE, &sa, &pager_process.orig_sigpipe);
+}
+
+/* Setup pager and redirects output to the $PAGER. The pager is closed at exit.
+ */
+void pager_redirect(void)
+{
+ if (pager_process.pid)
+ return; /* already running */
+
+ __setup_pager();
+
+ atexit(wait_for_pager);
+}
+
+/* Setup pager and redirect output, the pager may be closed by pager_close().
+ */
+void pager_open(void)
+{
+ if (pager_process.pid)
+ return; /* already running */
+
+ pager_process.org_out = dup(STDOUT_FILENO);
+ pager_process.org_err = dup(STDERR_FILENO);
+
+ __setup_pager();
+}
+
+/* Close pager and restore original std{out,err}.
+ */
+void pager_close(void)
+{
+ if (pager_process.pid == 0)
+ return;
+
+ wait_for_pager();
+
+ /* restore original output */
+ dup2(pager_process.org_out, STDOUT_FILENO);
+ dup2(pager_process.org_err, STDERR_FILENO);
+
+ close(pager_process.org_out);
+ close(pager_process.org_err);
+
+ /* restore original segnals setting */
+ sigaction(SIGINT, &pager_process.orig_sigint, NULL);
+ sigaction(SIGHUP, &pager_process.orig_sighup, NULL);
+ sigaction(SIGTERM, &pager_process.orig_sigterm, NULL);
+ sigaction(SIGQUIT, &pager_process.orig_sigquit, NULL);
+ sigaction(SIGPIPE, &pager_process.orig_sigpipe, NULL);
+
+ memset(&pager_process, 0, sizeof(pager_process));
+}
+
+#ifdef TEST_PROGRAM_PAGER
+
+#define MAX 255
+
+int main(int argc __attribute__ ((__unused__)),
+ char *argv[] __attribute__ ((__unused__)))
+{
+ int i;
+
+ pager_redirect();
+ for (i = 0; i < MAX; i++)
+ printf("%d\n", i);
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_PAGER */
diff --git a/src/utils/lib/path.c b/src/utils/lib/path.c
new file mode 100644
index 0000000..75fa853
--- /dev/null
+++ b/src/utils/lib/path.c
@@ -0,0 +1,1248 @@
+/*
+ * Simple functions to access files. Paths can be globally prefixed to read
+ * data from an alternative source (e.g. a /proc dump for regression tests).
+ *
+ * The paths is possible to format by printf-like way for functions with "f"
+ * postfix in the name (e.g. readf, openf, ... ul_path_readf_u64()).
+ *
+ * The ul_path_read_* API is possible to use without path_cxt handler. In this
+ * case is not possible to use global prefix and printf-like formatting.
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com> [February 2018]
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include "c.h"
+#include "fileutils.h"
+#include "all-io.h"
+#include "path.h"
+#include "debug.h"
+#include "strutils.h"
+
+/*
+ * Debug stuff (based on include/debug.h)
+ */
+static UL_DEBUG_DEFINE_MASK(ulpath);
+UL_DEBUG_DEFINE_MASKNAMES(ulpath) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define ULPATH_DEBUG_INIT (1 << 1)
+#define ULPATH_DEBUG_CXT (1 << 2)
+
+#define DBG(m, x) __UL_DBG(ulpath, ULPATH_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(ulpath, ULPATH_DEBUG_, m, x)
+
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpath)
+#include "debugobj.h"
+
+void ul_path_init_debug(void)
+{
+ if (ulpath_debug_mask)
+ return;
+ __UL_INIT_DEBUG_FROM_ENV(ulpath, ULPATH_DEBUG_, 0, ULPATH_DEBUG);
+}
+
+struct path_cxt *ul_new_path(const char *dir, ...)
+{
+ struct path_cxt *pc = calloc(1, sizeof(*pc));
+
+ if (!pc)
+ return NULL;
+
+ DBG(CXT, ul_debugobj(pc, "alloc"));
+
+ pc->refcount = 1;
+ pc->dir_fd = -1;
+
+ if (dir) {
+ int rc;
+ va_list ap;
+
+ va_start(ap, dir);
+ rc = vasprintf(&pc->dir_path, dir, ap);
+ va_end(ap);
+
+ if (rc < 0 || !pc->dir_path)
+ goto fail;
+ }
+ return pc;
+fail:
+ ul_unref_path(pc);
+ return NULL;
+}
+
+void ul_ref_path(struct path_cxt *pc)
+{
+ if (pc)
+ pc->refcount++;
+}
+
+void ul_unref_path(struct path_cxt *pc)
+{
+ if (!pc)
+ return;
+
+ pc->refcount--;
+
+ if (pc->refcount <= 0) {
+ DBG(CXT, ul_debugobj(pc, "dealloc"));
+ if (pc->dialect)
+ pc->free_dialect(pc);
+ ul_path_close_dirfd(pc);
+ free(pc->dir_path);
+ free(pc->prefix);
+ free(pc);
+ }
+}
+
+int ul_path_set_prefix(struct path_cxt *pc, const char *prefix)
+{
+ char *p = NULL;
+
+ assert(pc->dir_fd < 0);
+
+ if (prefix) {
+ p = strdup(prefix);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(pc->prefix);
+ pc->prefix = p;
+ DBG(CXT, ul_debugobj(pc, "new prefix: '%s'", p));
+ return 0;
+}
+
+const char *ul_path_get_prefix(struct path_cxt *pc)
+{
+ return pc ? pc->prefix : NULL;
+}
+
+int ul_path_set_dir(struct path_cxt *pc, const char *dir)
+{
+ char *p = NULL;
+
+ if (dir) {
+ p = strdup(dir);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ if (pc->dir_fd >= 0) {
+ close(pc->dir_fd);
+ pc->dir_fd = -1;
+ }
+
+ free(pc->dir_path);
+ pc->dir_path = p;
+ DBG(CXT, ul_debugobj(pc, "new dir: '%s'", p));
+ return 0;
+}
+
+const char *ul_path_get_dir(struct path_cxt *pc)
+{
+ return pc ? pc->dir_path : NULL;
+}
+
+int ul_path_set_dialect(struct path_cxt *pc, void *data, void free_data(struct path_cxt *))
+{
+ pc->dialect = data;
+ pc->free_dialect = free_data;
+ DBG(CXT, ul_debugobj(pc, "(re)set dialect"));
+ return 0;
+}
+
+void *ul_path_get_dialect(struct path_cxt *pc)
+{
+ return pc ? pc->dialect : NULL;
+}
+
+int ul_path_set_enoent_redirect(struct path_cxt *pc, int (*func)(struct path_cxt *, const char *, int *))
+{
+ pc->redirect_on_enoent = func;
+ return 0;
+}
+
+static const char *get_absdir(struct path_cxt *pc)
+{
+ int rc;
+ const char *dirpath;
+
+ if (!pc->prefix)
+ return pc->dir_path;
+
+ dirpath = pc->dir_path;
+ if (!dirpath)
+ return pc->prefix;
+ if (*dirpath == '/')
+ dirpath++;
+
+ rc = snprintf(pc->path_buffer, sizeof(pc->path_buffer), "%s/%s", pc->prefix, dirpath);
+ if (rc < 0)
+ return NULL;
+ if ((size_t)rc >= sizeof(pc->path_buffer)) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ return pc->path_buffer;
+}
+
+int ul_path_is_accessible(struct path_cxt *pc)
+{
+ const char *path;
+ assert(pc);
+
+ if (pc->dir_fd >= 0)
+ return 1;
+
+ path = get_absdir(pc);
+ if (!path)
+ return 0;
+ return access(path, F_OK) == 0;
+}
+
+int ul_path_get_dirfd(struct path_cxt *pc)
+{
+ assert(pc);
+ assert(pc->dir_path);
+
+ if (pc->dir_fd < 0) {
+ const char *path = get_absdir(pc);
+ if (!path)
+ return -errno;
+
+ DBG(CXT, ul_debugobj(pc, "opening dir: '%s'", path));
+ pc->dir_fd = open(path, O_RDONLY|O_CLOEXEC);
+ }
+
+ return pc->dir_fd;
+}
+
+/* Note that next ul_path_get_dirfd() will reopen the directory */
+void ul_path_close_dirfd(struct path_cxt *pc)
+{
+ assert(pc);
+
+ if (pc->dir_fd >= 0) {
+ DBG(CXT, ul_debugobj(pc, "closing dir"));
+ close(pc->dir_fd);
+ pc->dir_fd = -1;
+ }
+}
+
+int ul_path_isopen_dirfd(struct path_cxt *pc)
+{
+ return pc && pc->dir_fd >= 0;
+}
+
+static const char *ul_path_mkpath(struct path_cxt *pc, const char *path, va_list ap)
+{
+ int rc;
+
+ errno = 0;
+
+ rc = vsnprintf(pc->path_buffer, sizeof(pc->path_buffer), path, ap);
+ if (rc < 0) {
+ if (!errno)
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if ((size_t)rc >= sizeof(pc->path_buffer)) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ return pc->path_buffer;
+}
+
+char *ul_path_get_abspath(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...)
+{
+ if (path) {
+ int rc;
+ va_list ap;
+ const char *tail = NULL, *dirpath = pc->dir_path;
+
+ va_start(ap, path);
+ tail = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ if (dirpath && *dirpath == '/')
+ dirpath++;
+ if (tail && *tail == '/')
+ tail++;
+
+ rc = snprintf(buf, bufsz, "%s/%s/%s",
+ pc->prefix ? pc->prefix : "",
+ dirpath ? dirpath : "",
+ tail ? tail : "");
+
+ if ((size_t)rc >= bufsz) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ } else {
+ const char *tmp = get_absdir(pc);
+
+ if (!tmp)
+ return NULL;
+ xstrncpy(buf, tmp, bufsz);
+ }
+
+ return buf;
+}
+
+
+int ul_path_access(struct path_cxt *pc, int mode, const char *path)
+{
+ int rc;
+
+ if (!pc) {
+ rc = access(path, mode);
+ DBG(CXT, ul_debug("access '%s' [no context, rc=%d]", path, rc));
+ } else {
+ int dir = ul_path_get_dirfd(pc);
+ if (dir < 0)
+ return dir;
+ if (*path == '/')
+ path++;
+
+ rc = faccessat(dir, path, mode, 0);
+
+ if (rc && errno == ENOENT
+ && pc->redirect_on_enoent
+ && pc->redirect_on_enoent(pc, path, &dir) == 0)
+ rc = faccessat(dir, path, mode, 0);
+
+ DBG(CXT, ul_debugobj(pc, "access: '%s' [rc=%d]", path, rc));
+ }
+ return rc;
+}
+
+int ul_path_accessf(struct path_cxt *pc, int mode, const char *path, ...)
+{
+ va_list ap;
+ const char *p;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_access(pc, mode, p);
+}
+
+int ul_path_stat(struct path_cxt *pc, struct stat *sb, const char *path)
+{
+ int rc;
+
+ if (!pc) {
+ rc = stat(path, sb);
+ DBG(CXT, ul_debug("stat '%s' [no context, rc=%d]", path, rc));
+ } else {
+ int dir = ul_path_get_dirfd(pc);
+ if (dir < 0)
+ return dir;
+ if (*path == '/')
+ path++;
+
+ rc = fstatat(dir, path, sb, 0);
+
+ if (rc && errno == ENOENT
+ && pc->redirect_on_enoent
+ && pc->redirect_on_enoent(pc, path, &dir) == 0)
+ rc = fstatat(dir, path, sb, 0);
+
+ DBG(CXT, ul_debugobj(pc, "stat '%s' [rc=%d]", path, rc));
+ }
+ return rc;
+}
+
+int ul_path_open(struct path_cxt *pc, int flags, const char *path)
+{
+ int fd;
+
+ if (!pc) {
+ fd = open(path, flags);
+ DBG(CXT, ul_debug("opening '%s' [no context]", path));
+ } else {
+ int fdx;
+ int dir = ul_path_get_dirfd(pc);
+ if (dir < 0)
+ return dir;
+
+ if (*path == '/')
+ path++;
+
+ fdx = fd = openat(dir, path, flags);
+
+ if (fd < 0 && errno == ENOENT
+ && pc->redirect_on_enoent
+ && pc->redirect_on_enoent(pc, path, &dir) == 0)
+ fd = openat(dir, path, flags);
+
+ DBG(CXT, ul_debugobj(pc, "opening '%s'%s", path, fdx != fd ? " [redirected]" : ""));
+ }
+ return fd;
+}
+
+int ul_path_vopenf(struct path_cxt *pc, int flags, const char *path, va_list ap)
+{
+ const char *p = ul_path_mkpath(pc, path, ap);
+
+ return !p ? -errno : ul_path_open(pc, flags, p);
+}
+
+int ul_path_openf(struct path_cxt *pc, int flags, const char *path, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, path);
+ rc = ul_path_vopenf(pc, flags, path, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+/*
+ * Maybe stupid, but good enough ;-)
+ */
+static int mode2flags(const char *mode)
+{
+ int flags = 0;
+ const char *p;
+
+ for (p = mode; p && *p; p++) {
+ if (*p == 'r' && *(p + 1) == '+')
+ flags |= O_RDWR;
+ else if (*p == 'r')
+ flags |= O_RDONLY;
+
+ else if (*p == 'w' && *(p + 1) == '+')
+ flags |= O_RDWR | O_TRUNC;
+ else if (*p == 'w')
+ flags |= O_WRONLY | O_TRUNC;
+
+ else if (*p == 'a' && *(p + 1) == '+')
+ flags |= O_RDWR | O_APPEND;
+ else if (*p == 'a')
+ flags |= O_WRONLY | O_APPEND;
+#ifdef O_CLOEXEC
+ else if (*p == *UL_CLOEXECSTR)
+ flags |= O_CLOEXEC;
+#endif
+ }
+
+ return flags;
+}
+
+FILE *ul_path_fopen(struct path_cxt *pc, const char *mode, const char *path)
+{
+ int flags = mode2flags(mode);
+ int fd = ul_path_open(pc, flags, path);
+
+ if (fd < 0)
+ return NULL;
+
+ return fdopen(fd, mode);
+}
+
+
+FILE *ul_path_vfopenf(struct path_cxt *pc, const char *mode, const char *path, va_list ap)
+{
+ const char *p = ul_path_mkpath(pc, path, ap);
+
+ return !p ? NULL : ul_path_fopen(pc, mode, p);
+}
+
+FILE *ul_path_fopenf(struct path_cxt *pc, const char *mode, const char *path, ...)
+{
+ FILE *f;
+ va_list ap;
+
+ va_start(ap, path);
+ f = ul_path_vfopenf(pc, mode, path, ap);
+ va_end(ap);
+
+ return f;
+}
+
+/*
+ * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
+ * to the directory addressed by @pc.
+ */
+DIR *ul_path_opendir(struct path_cxt *pc, const char *path)
+{
+ DIR *dir;
+ int fd = -1;
+
+ if (path)
+ fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path);
+ else if (pc->dir_path) {
+ int dirfd;
+
+ DBG(CXT, ul_debugobj(pc, "duplicate dir path"));
+ dirfd = ul_path_get_dirfd(pc);
+ if (dirfd >= 0)
+ fd = dup_fd_cloexec(dirfd, STDERR_FILENO + 1);
+ }
+
+ if (fd < 0)
+ return NULL;
+
+ dir = fdopendir(fd);
+ if (!dir) {
+ close(fd);
+ return NULL;
+ }
+ if (!path)
+ rewinddir(dir);
+ return dir;
+}
+
+
+/*
+ * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
+ * to the directory addressed by @pc.
+ */
+DIR *ul_path_vopendirf(struct path_cxt *pc, const char *path, va_list ap)
+{
+ const char *p = ul_path_mkpath(pc, path, ap);
+
+ return !p ? NULL : ul_path_opendir(pc, p);
+}
+
+/*
+ * Open directory @path in read-onl mode. If the path is NULL then duplicate FD
+ * to the directory addressed by @pc.
+ */
+DIR *ul_path_opendirf(struct path_cxt *pc, const char *path, ...)
+{
+ va_list ap;
+ DIR *dir;
+
+ va_start(ap, path);
+ dir = ul_path_vopendirf(pc, path, ap);
+ va_end(ap);
+
+ return dir;
+}
+
+/*
+ * If @path is NULL then readlink is called on @pc directory.
+ */
+ssize_t ul_path_readlink(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path)
+{
+ int dirfd;
+
+ if (!path) {
+ const char *p = get_absdir(pc);
+ if (!p)
+ return -errno;
+ return readlink(p, buf, bufsiz);
+ }
+
+ dirfd = ul_path_get_dirfd(pc);
+ if (dirfd < 0)
+ return dirfd;
+
+ if (*path == '/')
+ path++;
+
+ return readlinkat(dirfd, path, buf, bufsiz);
+}
+
+/*
+ * If @path is NULL then readlink is called on @pc directory.
+ */
+ssize_t ul_path_readlinkf(struct path_cxt *pc, char *buf, size_t bufsiz, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_readlink(pc, buf, bufsiz, p);
+}
+
+int ul_path_read(struct path_cxt *pc, char *buf, size_t len, const char *path)
+{
+ int rc, errsv;
+ int fd;
+
+ fd = ul_path_open(pc, O_RDONLY|O_CLOEXEC, path);
+ if (fd < 0)
+ return -errno;
+
+ DBG(CXT, ul_debug(" reading '%s'", path));
+ rc = read_all(fd, buf, len);
+
+ errsv = errno;
+ close(fd);
+ errno = errsv;
+ return rc;
+}
+
+int ul_path_vreadf(struct path_cxt *pc, char *buf, size_t len, const char *path, va_list ap)
+{
+ const char *p = ul_path_mkpath(pc, path, ap);
+
+ return !p ? -errno : ul_path_read(pc, buf, len, p);
+}
+
+int ul_path_readf(struct path_cxt *pc, char *buf, size_t len, const char *path, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, path);
+ rc = ul_path_vreadf(pc, buf, len, path, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+
+/*
+ * Returns newly allocated buffer with data from file. Maximal size is BUFSIZ
+ * (send patch if you need something bigger;-)
+ *
+ * Returns size of the string!
+ */
+int ul_path_read_string(struct path_cxt *pc, char **str, const char *path)
+{
+ char buf[BUFSIZ];
+ int rc;
+
+ if (!str)
+ return -EINVAL;
+
+ *str = NULL;
+ rc = ul_path_read(pc, buf, sizeof(buf) - 1, path);
+ if (rc < 0)
+ return rc;
+
+ /* Remove tailing newline (usual in sysfs) */
+ if (rc > 0 && *(buf + rc - 1) == '\n')
+ --rc;
+
+ buf[rc] = '\0';
+ *str = strdup(buf);
+ if (!*str)
+ rc = -ENOMEM;
+
+ return rc;
+}
+
+int ul_path_readf_string(struct path_cxt *pc, char **str, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_string(pc, str, p);
+}
+
+int ul_path_read_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path)
+{
+ int rc = ul_path_read(pc, buf, bufsz - 1, path);
+ if (rc < 0)
+ return rc;
+
+ /* Remove tailing newline (usual in sysfs) */
+ if (rc > 0 && *(buf + rc - 1) == '\n')
+ buf[--rc] = '\0';
+ else
+ buf[rc - 1] = '\0';
+
+ return rc;
+}
+
+int ul_path_readf_buffer(struct path_cxt *pc, char *buf, size_t bufsz, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_buffer(pc, buf, bufsz, p);
+}
+
+int ul_path_scanf(struct path_cxt *pc, const char *path, const char *fmt, ...)
+{
+ FILE *f;
+ va_list fmt_ap;
+ int rc;
+
+ f = ul_path_fopen(pc, "r" UL_CLOEXECSTR, path);
+ if (!f)
+ return -EINVAL;
+
+ DBG(CXT, ul_debug(" fscanf [%s] '%s'", fmt, path));
+
+ va_start(fmt_ap, fmt);
+ rc = vfscanf(f, fmt, fmt_ap);
+ va_end(fmt_ap);
+
+ fclose(f);
+ return rc;
+}
+
+int ul_path_scanff(struct path_cxt *pc, const char *path, va_list ap, const char *fmt, ...)
+{
+ FILE *f;
+ va_list fmt_ap;
+ int rc;
+
+ f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap);
+ if (!f)
+ return -EINVAL;
+
+ va_start(fmt_ap, fmt);
+ rc = vfscanf(f, fmt, fmt_ap);
+ va_end(fmt_ap);
+
+ fclose(f);
+ return rc;
+}
+
+
+int ul_path_read_s64(struct path_cxt *pc, int64_t *res, const char *path)
+{
+ int64_t x = 0;
+ int rc;
+
+ rc = ul_path_scanf(pc, path, "%"SCNd64, &x);
+ if (rc != 1)
+ return -1;
+ if (res)
+ *res = x;
+ return 0;
+}
+
+int ul_path_readf_s64(struct path_cxt *pc, int64_t *res, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_s64(pc, res, p);
+}
+
+int ul_path_read_u64(struct path_cxt *pc, uint64_t *res, const char *path)
+{
+ uint64_t x = 0;
+ int rc;
+
+ rc = ul_path_scanf(pc, path, "%"SCNu64, &x);
+ if (rc != 1)
+ return -1;
+ if (res)
+ *res = x;
+ return 0;
+}
+
+int ul_path_readf_u64(struct path_cxt *pc, uint64_t *res, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_u64(pc, res, p);
+}
+
+int ul_path_read_s32(struct path_cxt *pc, int *res, const char *path)
+{
+ int rc, x = 0;
+
+ rc = ul_path_scanf(pc, path, "%d", &x);
+ if (rc != 1)
+ return -1;
+ if (res)
+ *res = x;
+ return 0;
+}
+
+int ul_path_readf_s32(struct path_cxt *pc, int *res, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_s32(pc, res, p);
+}
+
+int ul_path_read_u32(struct path_cxt *pc, unsigned int *res, const char *path)
+{
+ int rc;
+ unsigned int x;
+
+ rc = ul_path_scanf(pc, path, "%u", &x);
+ if (rc != 1)
+ return -1;
+ if (res)
+ *res = x;
+ return 0;
+}
+
+int ul_path_readf_u32(struct path_cxt *pc, unsigned int *res, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_u32(pc, res, p);
+}
+
+int ul_path_read_majmin(struct path_cxt *pc, dev_t *res, const char *path)
+{
+ int rc, maj, min;
+
+ rc = ul_path_scanf(pc, path, "%d:%d", &maj, &min);
+ if (rc != 2)
+ return -1;
+ if (res)
+ *res = makedev(maj, min);
+ return 0;
+}
+
+int ul_path_readf_majmin(struct path_cxt *pc, dev_t *res, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_read_majmin(pc, res, p);
+}
+
+int ul_path_write_string(struct path_cxt *pc, const char *str, const char *path)
+{
+ int rc, errsv;
+ int fd;
+
+ fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path);
+ if (fd < 0)
+ return -errno;
+
+ rc = write_all(fd, str, strlen(str));
+
+ errsv = errno;
+ close(fd);
+ errno = errsv;
+ return rc;
+}
+
+int ul_path_writef_string(struct path_cxt *pc, const char *str, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_write_string(pc, str, p);
+}
+
+int ul_path_write_s64(struct path_cxt *pc, int64_t num, const char *path)
+{
+ char buf[sizeof(stringify_value(LLONG_MAX))];
+ int rc, errsv;
+ int fd, len;
+
+ fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path);
+ if (fd < 0)
+ return -errno;
+
+ len = snprintf(buf, sizeof(buf), "%" PRId64, num);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ rc = len < 0 ? -errno : -E2BIG;
+ else
+ rc = write_all(fd, buf, len);
+
+ errsv = errno;
+ close(fd);
+ errno = errsv;
+ return rc;
+}
+
+int ul_path_write_u64(struct path_cxt *pc, uint64_t num, const char *path)
+{
+ char buf[sizeof(stringify_value(ULLONG_MAX))];
+ int rc, errsv;
+ int fd, len;
+
+ fd = ul_path_open(pc, O_WRONLY|O_CLOEXEC, path);
+ if (fd < 0)
+ return -errno;
+
+ len = snprintf(buf, sizeof(buf), "%" PRIu64, num);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ rc = len < 0 ? -errno : -E2BIG;
+ else
+ rc = write_all(fd, buf, len);
+
+ errsv = errno;
+ close(fd);
+ errno = errsv;
+ return rc;
+}
+
+int ul_path_writef_u64(struct path_cxt *pc, uint64_t num, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_write_u64(pc, num, p);
+
+}
+
+int ul_path_count_dirents(struct path_cxt *pc, const char *path)
+{
+ DIR *dir;
+ int r = 0;
+
+ dir = ul_path_opendir(pc, path);
+ if (!dir)
+ return 0;
+
+ while (xreaddir(dir)) r++;
+
+ closedir(dir);
+ return r;
+}
+
+int ul_path_countf_dirents(struct path_cxt *pc, const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = ul_path_mkpath(pc, path, ap);
+ va_end(ap);
+
+ return !p ? -errno : ul_path_count_dirents(pc, p);
+}
+
+/*
+ * Like fopen() but, @path is always prefixed by @prefix. This function is
+ * useful in case when ul_path_* API is overkill.
+ */
+FILE *ul_prefix_fopen(const char *prefix, const char *path, const char *mode)
+{
+ char buf[PATH_MAX];
+
+ if (!path)
+ return NULL;
+ if (!prefix)
+ return fopen(path, mode);
+ if (*path == '/')
+ path++;
+
+ snprintf(buf, sizeof(buf), "%s/%s", prefix, path);
+ return fopen(buf, mode);
+}
+
+#ifdef HAVE_CPU_SET_T
+static int ul_path_cpuparse(struct path_cxt *pc, cpu_set_t **set, int maxcpus, int islist, const char *path, va_list ap)
+{
+ FILE *f;
+ size_t setsize, len = maxcpus * 7;
+ char buf[len];
+ int rc;
+
+ *set = NULL;
+
+ f = ul_path_vfopenf(pc, "r" UL_CLOEXECSTR, path, ap);
+ if (!f)
+ return -errno;
+
+ rc = fgets(buf, len, f) == NULL ? -errno : 0;
+ fclose(f);
+
+ if (rc)
+ return rc;
+
+ len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ *set = cpuset_alloc(maxcpus, &setsize, NULL);
+ if (!*set)
+ return -ENOMEM;
+
+ if (islist) {
+ if (cpulist_parse(buf, *set, setsize, 0)) {
+ cpuset_free(*set);
+ return -EINVAL;
+ }
+ } else {
+ if (cpumask_parse(buf, *set, setsize)) {
+ cpuset_free(*set);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+int ul_path_readf_cpuset(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...)
+{
+ va_list ap;
+ int rc = 0;
+
+ va_start(ap, path);
+ rc = ul_path_cpuparse(pc, set, maxcpus, 0, path, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+int ul_path_readf_cpulist(struct path_cxt *pc, cpu_set_t **set, int maxcpus, const char *path, ...)
+{
+ va_list ap;
+ int rc = 0;
+
+ va_start(ap, path);
+ rc = ul_path_cpuparse(pc, set, maxcpus, 1, path, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+#endif /* HAVE_CPU_SET_T */
+
+
+#ifdef TEST_PROGRAM_PATH
+#include <getopt.h>
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ fprintf(stdout, " %s [options] <dir> <command>\n\n", program_invocation_short_name);
+ fputs(" -p, --prefix <dir> redirect hardcoded paths to <dir>\n", stdout);
+
+ fputs(" Commands:\n", stdout);
+ fputs(" read-u64 <file> read uint64_t from file\n", stdout);
+ fputs(" read-s64 <file> read int64_t from file\n", stdout);
+ fputs(" read-u32 <file> read uint32_t from file\n", stdout);
+ fputs(" read-s32 <file> read int32_t from file\n", stdout);
+ fputs(" read-string <file> read string from file\n", stdout);
+ fputs(" read-majmin <file> read devno from file\n", stdout);
+ fputs(" read-link <file> read symlink\n", stdout);
+ fputs(" write-string <file> <str> write string from file\n", stdout);
+ fputs(" write-u64 <file> <str> write uint64_t from file\n", stdout);
+
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ const char *prefix = NULL, *dir, *file, *command;
+ struct path_cxt *pc = NULL;
+
+ static const struct option longopts[] = {
+ { "prefix", 1, NULL, 'p' },
+ { "help", 0, NULL, 'h' },
+ { NULL, 0, NULL, 0 },
+ };
+
+ while((c = getopt_long(argc, argv, "p:h", longopts, NULL)) != -1) {
+ switch(c) {
+ case 'p':
+ prefix = optarg;
+ break;
+ case 'h':
+ usage();
+ break;
+ default:
+ err(EXIT_FAILURE, "try --help");
+ }
+ }
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<dir> not defined");
+ dir = argv[optind++];
+
+ ul_path_init_debug();
+
+ pc = ul_new_path(dir);
+ if (!pc)
+ err(EXIT_FAILURE, "failed to initialize path context");
+ if (prefix)
+ ul_path_set_prefix(pc, prefix);
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<command> not defined");
+ command = argv[optind++];
+
+ if (strcmp(command, "read-u32") == 0) {
+ uint32_t res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_u32(pc, &res, file) != 0)
+ err(EXIT_FAILURE, "read u64 failed");
+ printf("read: %s: %u\n", file, res);
+
+ if (ul_path_readf_u32(pc, &res, "%s", file) != 0)
+ err(EXIT_FAILURE, "readf u64 failed");
+ printf("readf: %s: %u\n", file, res);
+
+ } else if (strcmp(command, "read-s32") == 0) {
+ int32_t res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_s32(pc, &res, file) != 0)
+ err(EXIT_FAILURE, "read u64 failed");
+ printf("read: %s: %d\n", file, res);
+
+ if (ul_path_readf_s32(pc, &res, "%s", file) != 0)
+ err(EXIT_FAILURE, "readf u64 failed");
+ printf("readf: %s: %d\n", file, res);
+
+ } else if (strcmp(command, "read-u64") == 0) {
+ uint64_t res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_u64(pc, &res, file) != 0)
+ err(EXIT_FAILURE, "read u64 failed");
+ printf("read: %s: %" PRIu64 "\n", file, res);
+
+ if (ul_path_readf_u64(pc, &res, "%s", file) != 0)
+ err(EXIT_FAILURE, "readf u64 failed");
+ printf("readf: %s: %" PRIu64 "\n", file, res);
+
+ } else if (strcmp(command, "read-s64") == 0) {
+ int64_t res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_s64(pc, &res, file) != 0)
+ err(EXIT_FAILURE, "read u64 failed");
+ printf("read: %s: %" PRIu64 "\n", file, res);
+
+ if (ul_path_readf_s64(pc, &res, "%s", file) != 0)
+ err(EXIT_FAILURE, "readf u64 failed");
+ printf("readf: %s: %" PRIu64 "\n", file, res);
+
+ } else if (strcmp(command, "read-majmin") == 0) {
+ dev_t res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_majmin(pc, &res, file) != 0)
+ err(EXIT_FAILURE, "read maj:min failed");
+ printf("read: %s: %d\n", file, (int) res);
+
+ if (ul_path_readf_majmin(pc, &res, "%s", file) != 0)
+ err(EXIT_FAILURE, "readf maj:min failed");
+ printf("readf: %s: %d\n", file, (int) res);
+
+ } else if (strcmp(command, "read-string") == 0) {
+ char *res;
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_read_string(pc, &res, file) < 0)
+ err(EXIT_FAILURE, "read string failed");
+ printf("read: %s: %s\n", file, res);
+
+ if (ul_path_readf_string(pc, &res, "%s", file) < 0)
+ err(EXIT_FAILURE, "readf string failed");
+ printf("readf: %s: %s\n", file, res);
+
+ } else if (strcmp(command, "read-link") == 0) {
+ char res[PATH_MAX];
+
+ if (optind == argc)
+ errx(EXIT_FAILURE, "<file> not defined");
+ file = argv[optind++];
+
+ if (ul_path_readlink(pc, res, sizeof(res), file) < 0)
+ err(EXIT_FAILURE, "read symlink failed");
+ printf("read: %s: %s\n", file, res);
+
+ if (ul_path_readlinkf(pc, res, sizeof(res), "%s", file) < 0)
+ err(EXIT_FAILURE, "readf symlink failed");
+ printf("readf: %s: %s\n", file, res);
+
+ } else if (strcmp(command, "write-string") == 0) {
+ char *str;
+
+ if (optind + 1 == argc)
+ errx(EXIT_FAILURE, "<file> <string> not defined");
+ file = argv[optind++];
+ str = argv[optind++];
+
+ if (ul_path_write_string(pc, str, file) != 0)
+ err(EXIT_FAILURE, "write string failed");
+ if (ul_path_writef_string(pc, str, "%s", file) != 0)
+ err(EXIT_FAILURE, "writef string failed");
+
+ } else if (strcmp(command, "write-u64") == 0) {
+ uint64_t num;
+
+ if (optind + 1 == argc)
+ errx(EXIT_FAILURE, "<file> <num> not defined");
+ file = argv[optind++];
+ num = strtoumax(argv[optind++], NULL, 0);
+
+ if (ul_path_write_u64(pc, num, file) != 0)
+ err(EXIT_FAILURE, "write u64 failed");
+ if (ul_path_writef_u64(pc, num, "%s", file) != 0)
+ err(EXIT_FAILURE, "writef u64 failed");
+ }
+
+ ul_unref_path(pc);
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_PATH */
+
diff --git a/src/utils/lib/plymouth-ctrl.c b/src/utils/lib/plymouth-ctrl.c
new file mode 100644
index 0000000..2d3deda
--- /dev/null
+++ b/src/utils/lib/plymouth-ctrl.c
@@ -0,0 +1,144 @@
+/*
+ * plymouth-ctrl.c Simply communications with plymouthd
+ * to avoid forked sub processes and/or
+ * missed plymouth send commands tool
+ * due a plymouthd replacement.
+ *
+ * Copyright (c) 2016 SUSE Linux GmbH, All rights reserved.
+ * Copyright (c) 2016 Werner Fink <werner@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "all-io.h"
+#include "c.h"
+#include "nls.h"
+#include "plymouth-ctrl.h"
+
+static int can_read(int fd, const long timeout)
+{
+ struct pollfd fds = {
+ .fd = fd,
+ .events = POLLIN|POLLPRI,
+ .revents = 0,
+ };
+ int ret;
+
+ do {
+ ret = poll(&fds, 1, timeout);
+ } while ((ret < 0) && (errno == EINTR));
+
+ return (ret == 1) && (fds.revents & (POLLIN|POLLPRI));
+}
+
+static int open_un_socket_and_connect(void)
+{
+ /* The abstract UNIX socket of plymouth */
+ struct sockaddr_un su = {
+ .sun_family = AF_UNIX,
+ .sun_path = PLYMOUTH_SOCKET_PATH,
+ };
+ const int one = 1;
+ int fd, ret;
+
+ fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0) {
+ warnx(_("cannot open UNIX socket"));
+ goto err;
+ }
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ if (ret < 0) {
+ warnx(_("cannot set option for UNIX socket"));
+ close(fd);
+ fd = -1;
+ goto err;
+ }
+
+ /* Note, the abstract PLYMOUTH_SOCKET_PATH has a leading NULL byte */
+ ret = connect(fd, (struct sockaddr *) &su,
+ offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1));
+ if (ret < 0) {
+ if (errno != ECONNREFUSED)
+ warnx(_("cannot connect on UNIX socket"));
+ close(fd);
+ fd = -1;
+ goto err;
+ }
+err:
+ return fd;
+}
+
+int plymouth_command(int cmd, ...)
+{
+ uint8_t answer[2], command[2];
+ struct sigaction sp, op;
+ int fdsock = -1, ret = 0;
+
+ sigemptyset (&sp.sa_mask);
+ sp.sa_handler = SIG_IGN;
+ sp.sa_flags = SA_RESTART;
+ sigaction(SIGPIPE, &sp, &op);
+
+ /* The plymouthd does read at least two bytes. */
+ command[1] = '\0';
+ switch (cmd) {
+ case MAGIC_PING:
+ fdsock = open_un_socket_and_connect();
+ if (fdsock >= 0) {
+ command[0] = cmd;
+ write_all(fdsock, command, sizeof(command));
+ }
+ break;
+ case MAGIC_QUIT:
+ fdsock = open_un_socket_and_connect();
+ if (fdsock >= 0) {
+ command[0] = cmd;
+ write_all(fdsock, command, sizeof(command));
+ }
+ break;
+ default:
+ warnx(_("the plymouth request %c is not implemented"), cmd);
+ case '?':
+ goto err;
+ }
+
+ answer[0] = '\0';
+ if (fdsock >= 0) {
+ if (can_read(fdsock, 1000))
+ read_all(fdsock, (char *) &answer[0], sizeof(answer));
+ close(fdsock);
+ }
+ sigaction(SIGPIPE, &op, NULL);
+ ret = (answer[0] == ANSWER_ACK) ? 1 : 0;
+err:
+ return ret;
+}
+
diff --git a/src/utils/lib/procutils.c b/src/utils/lib/procutils.c
new file mode 100644
index 0000000..8fb5d5c
--- /dev/null
+++ b/src/utils/lib/procutils.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
+ *
+ * procutils.c: General purpose procfs parsing utilities
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library Public License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+
+#include "procutils.h"
+#include "fileutils.h"
+#include "all-io.h"
+#include "c.h"
+
+/*
+ * @pid: process ID for which we want to obtain the threads group
+ *
+ * Returns: newly allocated tasks structure
+ */
+struct proc_tasks *proc_open_tasks(pid_t pid)
+{
+ struct proc_tasks *tasks;
+ char path[PATH_MAX];
+
+ sprintf(path, "/proc/%d/task/", pid);
+
+ tasks = malloc(sizeof(struct proc_tasks));
+ if (tasks) {
+ tasks->dir = opendir(path);
+ if (tasks->dir)
+ return tasks;
+ }
+
+ free(tasks);
+ return NULL;
+}
+
+/*
+ * @tasks: allocated tasks structure
+ *
+ * Returns: nothing
+ */
+void proc_close_tasks(struct proc_tasks *tasks)
+{
+ if (tasks && tasks->dir)
+ closedir(tasks->dir);
+ free(tasks);
+}
+
+/*
+ * @tasks: allocated task structure
+ * @tid: [output] one of the thread IDs belonging to the thread group
+ * If when an error occurs, it is set to 0.
+ *
+ * Returns: 0 on success, 1 on end, -1 on failure or no more threads
+ */
+int proc_next_tid(struct proc_tasks *tasks, pid_t *tid)
+{
+ struct dirent *d;
+ char *end;
+
+ if (!tasks || !tid)
+ return -EINVAL;
+
+ *tid = 0;
+ errno = 0;
+
+ do {
+ d = readdir(tasks->dir);
+ if (!d)
+ return errno ? -1 : 1; /* error or end-of-dir */
+
+ if (!isdigit((unsigned char) *d->d_name))
+ continue;
+ errno = 0;
+ *tid = (pid_t) strtol(d->d_name, &end, 10);
+ if (errno || d->d_name == end || (end && *end))
+ return -1;
+
+ } while (!*tid);
+
+ return 0;
+}
+
+/* returns process command path, use free() for result */
+static char *proc_file_strdup(pid_t pid, const char *name)
+{
+ char buf[BUFSIZ], *res = NULL;
+ ssize_t sz = 0;
+ size_t i;
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/%s", (int) pid, name);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ goto done;
+
+ sz = read_all(fd, buf, sizeof(buf));
+ if (sz <= 0)
+ goto done;
+
+ for (i = 0; i < (size_t) sz; i++) {
+
+ if (buf[i] == '\0')
+ buf[i] = ' ';
+ }
+ buf[sz - 1] = '\0';
+ res = strdup(buf);
+done:
+ if (fd >= 0)
+ close(fd);
+ return res;
+}
+
+/* returns process command path, use free() for result */
+char *proc_get_command(pid_t pid)
+{
+ return proc_file_strdup(pid, "cmdline");
+}
+
+/* returns process command name, use free() for result */
+char *proc_get_command_name(pid_t pid)
+{
+ return proc_file_strdup(pid, "comm");
+}
+
+struct proc_processes *proc_open_processes(void)
+{
+ struct proc_processes *ps;
+
+ ps = calloc(1, sizeof(struct proc_processes));
+ if (ps) {
+ ps->dir = opendir("/proc");
+ if (ps->dir)
+ return ps;
+ }
+
+ free(ps);
+ return NULL;
+}
+
+void proc_close_processes(struct proc_processes *ps)
+{
+ if (ps && ps->dir)
+ closedir(ps->dir);
+ free(ps);
+}
+
+void proc_processes_filter_by_name(struct proc_processes *ps, const char *name)
+{
+ ps->fltr_name = name;
+ ps->has_fltr_name = name ? 1 : 0;
+}
+
+void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid)
+{
+ ps->fltr_uid = uid;
+ ps->has_fltr_uid = 1;
+}
+
+int proc_next_pid(struct proc_processes *ps, pid_t *pid)
+{
+ struct dirent *d;
+
+ if (!ps || !pid)
+ return -EINVAL;
+
+ *pid = 0;
+ errno = 0;
+
+ do {
+ char buf[BUFSIZ], *p;
+
+ errno = 0;
+ d = readdir(ps->dir);
+ if (!d)
+ return errno ? -1 : 1; /* error or end-of-dir */
+
+
+ if (!isdigit((unsigned char) *d->d_name))
+ continue;
+
+ /* filter out by UID */
+ if (ps->has_fltr_uid) {
+ struct stat st;
+
+ if (fstatat(dirfd(ps->dir), d->d_name, &st, 0))
+ continue;
+ if (ps->fltr_uid != st.st_uid)
+ continue;
+ }
+
+ /* filter out by NAME */
+ if (ps->has_fltr_name) {
+ char procname[256];
+ FILE *f;
+
+ snprintf(buf, sizeof(buf), "%s/stat", d->d_name);
+ f = fopen_at(dirfd(ps->dir), buf, O_CLOEXEC|O_RDONLY, "r");
+ if (!f)
+ continue;
+
+ p = fgets(buf, sizeof(buf), f);
+ fclose(f);
+ if (!p)
+ continue;
+
+ if (sscanf(buf, "%*d (%255[^)])", procname) != 1)
+ continue;
+
+ /* ok, we got the process name. */
+ if (strcmp(procname, ps->fltr_name) != 0)
+ continue;
+ }
+
+ p = NULL;
+ errno = 0;
+ *pid = (pid_t) strtol(d->d_name, &p, 10);
+ if (errno || d->d_name == p || (p && *p))
+ return errno ? -errno : -1;
+
+ return 0;
+ } while (1);
+
+ return 0;
+}
+
+#ifdef TEST_PROGRAM_PROCUTILS
+
+static int test_tasks(int argc, char *argv[])
+{
+ pid_t tid, pid;
+ struct proc_tasks *ts;
+
+ if (argc != 2)
+ return EXIT_FAILURE;
+
+ pid = strtol(argv[1], (char **) NULL, 10);
+ printf("PID=%d, TIDs:", pid);
+
+ ts = proc_open_tasks(pid);
+ if (!ts)
+ err(EXIT_FAILURE, "open list of tasks failed");
+
+ while (proc_next_tid(ts, &tid) == 0)
+ printf(" %d", tid);
+
+ printf("\n");
+ proc_close_tasks(ts);
+ return EXIT_SUCCESS;
+}
+
+static int test_processes(int argc, char *argv[])
+{
+ pid_t pid;
+ struct proc_processes *ps;
+
+ ps = proc_open_processes();
+ if (!ps)
+ err(EXIT_FAILURE, "open list of processes failed");
+
+ if (argc >= 3 && strcmp(argv[1], "--name") == 0)
+ proc_processes_filter_by_name(ps, argv[2]);
+
+ if (argc >= 3 && strcmp(argv[1], "--uid") == 0)
+ proc_processes_filter_by_uid(ps, (uid_t) atol(argv[2]));
+
+ while (proc_next_pid(ps, &pid) == 0)
+ printf(" %d", pid);
+
+ printf("\n");
+ proc_close_processes(ps);
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %1$s --tasks <pid>\n"
+ " %1$s --processes [---name <name>] [--uid <uid>]\n",
+ program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+
+ if (strcmp(argv[1], "--tasks") == 0)
+ return test_tasks(argc - 1, argv + 1);
+ if (strcmp(argv[1], "--processes") == 0)
+ return test_processes(argc - 1, argv + 1);
+
+ return EXIT_FAILURE;
+}
+#endif /* TEST_PROGRAM_PROCUTILS */
diff --git a/src/utils/lib/pty-session.c b/src/utils/lib/pty-session.c
new file mode 100644
index 0000000..06b2a49
--- /dev/null
+++ b/src/utils/lib/pty-session.c
@@ -0,0 +1,725 @@
+/*
+ * This is pseudo-terminal container for child process where parent creates a
+ * proxy between the current std{in,out,etrr} and the child's pty. Advantages:
+ *
+ * - child has no access to parent's terminal (e.g. su --pty)
+ * - parent can log all traffic between user and child's terminal (e.g. script(1))
+ * - it's possible to start commands on terminal although parent has no terminal
+ *
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com> in Jul 2019
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <pty.h>
+#include <poll.h>
+#include <sys/signalfd.h>
+#include <paths.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "c.h"
+#include "all-io.h"
+#include "ttyutils.h"
+#include "pty-session.h"
+#include "monotonic.h"
+#include "debug.h"
+
+static UL_DEBUG_DEFINE_MASK(ulpty);
+UL_DEBUG_DEFINE_MASKNAMES(ulpty) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define ULPTY_DEBUG_INIT (1 << 1)
+#define ULPTY_DEBUG_SETUP (1 << 2)
+#define ULPTY_DEBUG_SIG (1 << 3)
+#define ULPTY_DEBUG_IO (1 << 4)
+#define ULPTY_DEBUG_DONE (1 << 5)
+#define ULPTY_DEBUG_ALL 0xFFFF
+
+#define DBG(m, x) __UL_DBG(ulpty, ULPTY_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(ulpty, ULPTY_DEBUG_, m, x)
+
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpty)
+#include "debugobj.h"
+
+void ul_pty_init_debug(int mask)
+{
+ if (ulpty_debug_mask)
+ return;
+ __UL_INIT_DEBUG_FROM_ENV(ulpty, ULPTY_DEBUG_, mask, ULPTY_DEBUG);
+}
+
+struct ul_pty *ul_new_pty(int is_stdin_tty)
+{
+ struct ul_pty *pty = calloc(1, sizeof(*pty));
+
+ if (!pty)
+ return NULL;
+
+ DBG(SETUP, ul_debugobj(pty, "alloc handler"));
+ pty->isterm = is_stdin_tty;
+ pty->master = -1;
+ pty->slave = -1;
+ pty->sigfd = -1;
+ pty->child = (pid_t) -1;
+
+ return pty;
+}
+
+void ul_free_pty(struct ul_pty *pty)
+{
+ free(pty);
+}
+
+void ul_pty_slave_echo(struct ul_pty *pty, int enable)
+{
+ assert(pty);
+ pty->slave_echo = enable ? 1 : 0;
+}
+
+int ul_pty_get_delivered_signal(struct ul_pty *pty)
+{
+ assert(pty);
+ return pty->delivered_signal;
+}
+
+struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty)
+{
+ assert(pty);
+ return &pty->callbacks;
+}
+
+void ul_pty_set_callback_data(struct ul_pty *pty, void *data)
+{
+ assert(pty);
+ pty->callback_data = data;
+}
+
+void ul_pty_set_child(struct ul_pty *pty, pid_t child)
+{
+ assert(pty);
+ pty->child = child;
+}
+
+int ul_pty_get_childfd(struct ul_pty *pty)
+{
+ assert(pty);
+ return pty->master;
+}
+
+pid_t ul_pty_get_child(struct ul_pty *pty)
+{
+ assert(pty);
+ return pty->child;
+}
+
+/* it's active when signals are redirected to sigfd */
+int ul_pty_is_running(struct ul_pty *pty)
+{
+ assert(pty);
+ return pty->sigfd >= 0;
+}
+
+void ul_pty_set_mainloop_time(struct ul_pty *pty, struct timeval *tv)
+{
+ assert(pty);
+ if (!tv) {
+ DBG(IO, ul_debugobj(pty, "mainloop time: clear"));
+ timerclear(&pty->next_callback_time);
+ } else {
+ pty->next_callback_time.tv_sec = tv->tv_sec;
+ pty->next_callback_time.tv_usec = tv->tv_usec;
+ DBG(IO, ul_debugobj(pty, "mainloop time: %ld.%06ld", tv->tv_sec, tv->tv_usec));
+ }
+}
+
+static void pty_signals_cleanup(struct ul_pty *pty)
+{
+ if (pty->sigfd != -1)
+ close(pty->sigfd);
+ pty->sigfd = -1;
+
+ /* restore original setting */
+ sigprocmask(SIG_SETMASK, &pty->orgsig, NULL);
+}
+
+/* call me before fork() */
+int ul_pty_setup(struct ul_pty *pty)
+{
+ struct termios attrs;
+ sigset_t ourset;
+ int rc = 0;
+
+ assert(pty->sigfd == -1);
+
+ /* save the current signals setting */
+ sigprocmask(0, NULL, &pty->orgsig);
+
+ if (pty->isterm) {
+ DBG(SETUP, ul_debugobj(pty, "create for terminal"));
+
+ /* original setting of the current terminal */
+ if (tcgetattr(STDIN_FILENO, &pty->stdin_attrs) != 0) {
+ rc = -errno;
+ goto done;
+ }
+
+ attrs = pty->stdin_attrs;
+ if (pty->slave_echo)
+ attrs.c_lflag |= ECHO;
+ else
+ attrs.c_lflag &= ~ECHO;
+
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win);
+ /* create master+slave */
+ rc = openpty(&pty->master, &pty->slave, NULL, &attrs, &pty->win);
+ if (rc)
+ goto done;
+
+ /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */
+ cfmakeraw(&attrs);
+ tcsetattr(STDIN_FILENO, TCSANOW, &attrs);
+ } else {
+ DBG(SETUP, ul_debugobj(pty, "create for non-terminal"));
+
+ rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL);
+ if (rc)
+ goto done;
+
+ tcgetattr(pty->slave, &attrs);
+
+ if (pty->slave_echo)
+ attrs.c_lflag |= ECHO;
+ else
+ attrs.c_lflag &= ~ECHO;
+
+ tcsetattr(pty->slave, TCSANOW, &attrs);
+ }
+
+ sigfillset(&ourset);
+ if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
+ rc = -errno;
+ goto done;
+ }
+
+ sigemptyset(&ourset);
+ sigaddset(&ourset, SIGCHLD);
+ sigaddset(&ourset, SIGWINCH);
+ sigaddset(&ourset, SIGALRM);
+ sigaddset(&ourset, SIGTERM);
+ sigaddset(&ourset, SIGINT);
+ sigaddset(&ourset, SIGQUIT);
+
+ if (pty->callbacks.flush_logs)
+ sigaddset(&ourset, SIGUSR1);
+
+ if ((pty->sigfd = signalfd(-1, &ourset, SFD_CLOEXEC)) < 0)
+ rc = -errno;
+done:
+ if (rc)
+ ul_pty_cleanup(pty);
+
+ DBG(SETUP, ul_debugobj(pty, "pty setup done [master=%d, slave=%d, rc=%d]",
+ pty->master, pty->slave, rc));
+ return rc;
+}
+
+/* cleanup in parent process */
+void ul_pty_cleanup(struct ul_pty *pty)
+{
+ struct termios rtt;
+
+ pty_signals_cleanup(pty);
+
+ if (pty->master == -1 || !pty->isterm)
+ return;
+
+ DBG(DONE, ul_debugobj(pty, "cleanup"));
+ rtt = pty->stdin_attrs;
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &rtt);
+}
+
+/* call me in child process */
+void ul_pty_init_slave(struct ul_pty *pty)
+{
+ DBG(SETUP, ul_debugobj(pty, "initialize slave"));
+
+ setsid();
+
+ ioctl(pty->slave, TIOCSCTTY, 1);
+ close(pty->master);
+
+ dup2(pty->slave, STDIN_FILENO);
+ dup2(pty->slave, STDOUT_FILENO);
+ dup2(pty->slave, STDERR_FILENO);
+
+ close(pty->slave);
+
+ if (pty->sigfd >= 0)
+ close(pty->sigfd);
+
+ pty->slave = -1;
+ pty->master = -1;
+ pty->sigfd = -1;
+
+ sigprocmask(SIG_SETMASK, &pty->orgsig, NULL);
+
+ DBG(SETUP, ul_debugobj(pty, "... initialize slave done"));
+}
+
+static int write_output(char *obuf, ssize_t bytes)
+{
+ DBG(IO, ul_debug(" writing output"));
+
+ if (write_all(STDOUT_FILENO, obuf, bytes)) {
+ DBG(IO, ul_debug(" writing output *failed*"));
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int write_to_child(struct ul_pty *pty, char *buf, size_t bufsz)
+{
+ return write_all(pty->master, buf, bufsz);
+}
+
+/*
+ * The pty is usually faster than shell, so it's a good idea to wait until
+ * the previous message has been already read by shell from slave before we
+ * write to master. This is necessary especially for EOF situation when we can
+ * send EOF to master before shell is fully initialized, to workaround this
+ * problem we wait until slave is empty. For example:
+ *
+ * echo "date" | su --pty
+ *
+ * Unfortunately, the child (usually shell) can ignore stdin at all, so we
+ * don't wait forever to avoid dead locks...
+ *
+ * Note that su --pty is primarily designed for interactive sessions as it
+ * maintains master+slave tty stuff within the session. Use pipe to write to
+ * pty and assume non-interactive (tee-like) behavior is NOT well supported.
+ */
+void ul_pty_write_eof_to_child(struct ul_pty *pty)
+{
+ unsigned int tries = 0;
+ struct pollfd fds[] = {
+ { .fd = pty->slave, .events = POLLIN }
+ };
+ char c = DEF_EOF;
+
+ DBG(IO, ul_debugobj(pty, " waiting for empty slave"));
+ while (poll(fds, 1, 10) == 1 && tries < 8) {
+ DBG(IO, ul_debugobj(pty, " slave is not empty"));
+ xusleep(250000);
+ tries++;
+ }
+ if (tries < 8)
+ DBG(IO, ul_debugobj(pty, " slave is empty now"));
+
+ DBG(IO, ul_debugobj(pty, " sending EOF to master"));
+ write_to_child(pty, &c, sizeof(char));
+}
+
+static int mainloop_callback(struct ul_pty *pty)
+{
+ int rc;
+
+ if (!pty->callbacks.mainloop)
+ return 0;
+
+ DBG(IO, ul_debugobj(pty, "calling mainloop callback"));
+ rc = pty->callbacks.mainloop(pty->callback_data);
+
+ DBG(IO, ul_debugobj(pty, " callback done [rc=%d]", rc));
+ return rc;
+}
+
+static int handle_io(struct ul_pty *pty, int fd, int *eof)
+{
+ char buf[BUFSIZ];
+ ssize_t bytes;
+ int rc = 0;
+
+ DBG(IO, ul_debugobj(pty, " handle I/O on fd=%d", fd));
+ *eof = 0;
+
+ /* read from active FD */
+ bytes = read(fd, buf, sizeof(buf));
+ if (bytes < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+ return -errno;
+ }
+
+ if (bytes == 0) {
+ *eof = 1;
+ return 0;
+ }
+
+ /* from stdin (user) to command */
+ if (fd == STDIN_FILENO) {
+ DBG(IO, ul_debugobj(pty, " stdin --> master %zd bytes", bytes));
+
+ if (write_to_child(pty, buf, bytes))
+ return -errno;
+
+ /* without sync write_output() will write both input &
+ * shell output that looks like double echoing */
+ fdatasync(pty->master);
+
+ /* from command (master) to stdout */
+ } else if (fd == pty->master) {
+ DBG(IO, ul_debugobj(pty, " master --> stdout %zd bytes", bytes));
+ write_output(buf, bytes);
+ }
+
+ if (pty->callbacks.log_stream_activity)
+ rc = pty->callbacks.log_stream_activity(
+ pty->callback_data, fd, buf, bytes);
+
+ return rc;
+}
+
+void ul_pty_wait_for_child(struct ul_pty *pty)
+{
+ int status;
+ pid_t pid;
+ int options = 0;
+
+ if (pty->child == (pid_t) -1)
+ return;
+
+ DBG(SIG, ul_debug("waiting for child [child=%d]", (int) pty->child));
+
+ if (ul_pty_is_running(pty)) {
+ /* wait for specific child */
+ options = WNOHANG;
+ for (;;) {
+ pid = waitpid(pty->child, &status, options);
+ DBG(SIG, ul_debug(" waitpid done [rc=%d]", (int) pid));
+ if (pid != (pid_t) - 1) {
+ if (pty->callbacks.child_die)
+ pty->callbacks.child_die(
+ pty->callback_data,
+ pty->child, status);
+ ul_pty_set_child(pty, (pid_t) -1);
+ } else
+ break;
+ }
+ } else {
+ /* final wait */
+ while ((pid = wait3(&status, options, NULL)) > 0) {
+ DBG(SIG, ul_debug(" wait3 done [rc=%d]", (int) pid));
+ if (pid == pty->child) {
+ if (pty->callbacks.child_die)
+ pty->callbacks.child_die(
+ pty->callback_data,
+ pty->child, status);
+ ul_pty_set_child(pty, (pid_t) -1);
+ }
+ }
+ }
+}
+
+static int handle_signal(struct ul_pty *pty, int fd)
+{
+ struct signalfd_siginfo info;
+ ssize_t bytes;
+ int rc = 0;
+
+ DBG(SIG, ul_debugobj(pty, " handle signal on fd=%d", fd));
+
+ bytes = read(fd, &info, sizeof(info));
+ if (bytes != sizeof(info)) {
+ if (bytes < 0 && (errno == EAGAIN || errno == EINTR))
+ return 0;
+ return -errno;
+ }
+
+ switch (info.ssi_signo) {
+ case SIGCHLD:
+ DBG(SIG, ul_debugobj(pty, " get signal SIGCHLD"));
+
+ if (info.ssi_code == CLD_EXITED
+ || info.ssi_code == CLD_KILLED
+ || info.ssi_code == CLD_DUMPED) {
+
+ if (pty->callbacks.child_wait)
+ pty->callbacks.child_wait(pty->callback_data,
+ pty->child);
+ else
+ ul_pty_wait_for_child(pty);
+
+ } else if (info.ssi_status == SIGSTOP && pty->child > 0)
+ pty->callbacks.child_sigstop(pty->callback_data,
+ pty->child);
+
+ if (pty->child <= 0) {
+ DBG(SIG, ul_debugobj(pty, " no child, setting leaving timeout"));
+ pty->poll_timeout = 10;
+ timerclear(&pty->next_callback_time);
+ }
+ return 0;
+ case SIGWINCH:
+ DBG(SIG, ul_debugobj(pty, " get signal SIGWINCH"));
+ if (pty->isterm) {
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win);
+ ioctl(pty->slave, TIOCSWINSZ, (char *)&pty->win);
+
+ if (pty->callbacks.log_signal)
+ rc = pty->callbacks.log_signal(pty->callback_data,
+ &info, (void *) &pty->win);
+ }
+ break;
+ case SIGTERM:
+ /* fallthrough */
+ case SIGINT:
+ /* fallthrough */
+ case SIGQUIT:
+ DBG(SIG, ul_debugobj(pty, " get signal SIG{TERM,INT,QUIT}"));
+ pty->delivered_signal = info.ssi_signo;
+ /* Child termination is going to generate SIGCHLD (see above) */
+ if (pty->child > 0)
+ kill(pty->child, SIGTERM);
+
+ if (pty->callbacks.log_signal)
+ rc = pty->callbacks.log_signal(pty->callback_data,
+ &info, (void *) &pty->win);
+ break;
+ case SIGUSR1:
+ DBG(SIG, ul_debugobj(pty, " get signal SIGUSR1"));
+ if (pty->callbacks.flush_logs)
+ rc = pty->callbacks.flush_logs(pty->callback_data);
+ break;
+ default:
+ abort();
+ }
+
+ return rc;
+}
+
+/* loop in parent */
+int ul_pty_proxy_master(struct ul_pty *pty)
+{
+ int rc = 0, ret, eof = 0;
+ enum {
+ POLLFD_SIGNAL = 0,
+ POLLFD_MASTER,
+ POLLFD_STDIN
+
+ };
+ struct pollfd pfd[] = {
+ [POLLFD_SIGNAL] = { .fd = -1, .events = POLLIN | POLLERR | POLLHUP },
+ [POLLFD_MASTER] = { .fd = pty->master, .events = POLLIN | POLLERR | POLLHUP },
+ [POLLFD_STDIN] = { .fd = STDIN_FILENO, .events = POLLIN | POLLERR | POLLHUP }
+ };
+
+ /* We use signalfd, and standard signals by handlers are completely blocked */
+ assert(pty->sigfd >= 0);
+
+ pfd[POLLFD_SIGNAL].fd = pty->sigfd;
+ pty->poll_timeout = -1;
+
+ while (!pty->delivered_signal) {
+ size_t i;
+ int errsv, timeout;
+
+ DBG(IO, ul_debugobj(pty, "--poll() loop--"));
+
+ /* note, callback usually updates @next_callback_time */
+ if (timerisset(&pty->next_callback_time)) {
+ struct timeval now;
+
+ DBG(IO, ul_debugobj(pty, " callback requested"));
+ gettime_monotonic(&now);
+ if (timercmp(&now, &pty->next_callback_time, >)) {
+ rc = mainloop_callback(pty);
+ if (rc)
+ break;
+ }
+ }
+
+ /* set timeout */
+ if (timerisset(&pty->next_callback_time)) {
+ struct timeval now, rest;
+
+ gettime_monotonic(&now);
+ timersub(&pty->next_callback_time, &now, &rest);
+ timeout = (rest.tv_sec * 1000) + (rest.tv_usec / 1000);
+ } else
+ timeout = pty->poll_timeout;
+
+ /* wait for input, signal or timeout */
+ DBG(IO, ul_debugobj(pty, "calling poll() [timeout=%dms]", timeout));
+ ret = poll(pfd, ARRAY_SIZE(pfd), timeout);
+
+ errsv = errno;
+ DBG(IO, ul_debugobj(pty, "poll() rc=%d", ret));
+
+ /* error */
+ if (ret < 0) {
+ if (errsv == EAGAIN)
+ continue;
+ rc = -errno;
+ break;
+ }
+
+ /* timeout */
+ if (ret == 0) {
+ if (timerisset(&pty->next_callback_time)) {
+ rc = mainloop_callback(pty);
+ if (rc == 0)
+ continue;
+ } else
+ rc = 0;
+
+ DBG(IO, ul_debugobj(pty, "leaving poll() loop [timeout=%d, rc=%d]", timeout, rc));
+ break;
+ }
+ /* event */
+ for (i = 0; i < ARRAY_SIZE(pfd); i++) {
+ rc = 0;
+
+ if (pfd[i].revents == 0)
+ continue;
+
+ DBG(IO, ul_debugobj(pty, " active pfd[%s].fd=%d %s %s %s %s",
+ i == POLLFD_STDIN ? "stdin" :
+ i == POLLFD_MASTER ? "master" :
+ i == POLLFD_SIGNAL ? "signal" : "???",
+ pfd[i].fd,
+ pfd[i].revents & POLLIN ? "POLLIN" : "",
+ pfd[i].revents & POLLHUP ? "POLLHUP" : "",
+ pfd[i].revents & POLLERR ? "POLLERR" : "",
+ pfd[i].revents & POLLNVAL ? "POLLNVAL" : ""));
+
+ switch (i) {
+ case POLLFD_STDIN:
+ case POLLFD_MASTER:
+ /* data */
+ if (pfd[i].revents & POLLIN)
+ rc = handle_io(pty, pfd[i].fd, &eof);
+ /* EOF maybe detected in two ways; they are as follows:
+ * A) poll() return POLLHUP event after close()
+ * B) read() returns 0 (no data)
+ *
+ * POLLNVAL means that fd is closed.
+ */
+ if ((pfd[i].revents & POLLHUP) || (pfd[i].revents & POLLNVAL) || eof) {
+ DBG(IO, ul_debugobj(pty, " ignore FD"));
+ pfd[i].fd = -1;
+ if (i == POLLFD_STDIN) {
+ ul_pty_write_eof_to_child(pty);
+ DBG(IO, ul_debugobj(pty, " ignore STDIN"));
+ }
+ }
+ continue;
+ case POLLFD_SIGNAL:
+ rc = handle_signal(pty, pfd[i].fd);
+ break;
+ }
+ if (rc)
+ break;
+ }
+ }
+
+ pty_signals_cleanup(pty);
+
+ DBG(IO, ul_debug("poll() done [signal=%d, rc=%d]", pty->delivered_signal, rc));
+ return rc;
+}
+
+#ifdef TEST_PROGRAM_PTY
+/*
+ * $ make test_pty
+ * $ ./test_pty
+ *
+ * ... and see for example tty(1) or "ps afu"
+ */
+static void child_sigstop(void *data __attribute__((__unused__)), pid_t child)
+{
+ kill(getpid(), SIGSTOP);
+ kill(child, SIGCONT);
+}
+
+int main(int argc, char *argv[])
+{
+ struct ul_pty_callbacks *cb;
+ const char *shell, *command = NULL, *shname = NULL;
+ int caught_signal = 0;
+ pid_t child;
+ struct ul_pty *pty;
+
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = _PATH_BSHELL;
+ if (argc == 2)
+ command = argv[1];
+
+ ul_pty_init_debug(0);
+
+ pty = ul_new_pty(isatty(STDIN_FILENO));
+ if (!pty)
+ err(EXIT_FAILURE, "failed to allocate PTY handler");
+
+ cb = ul_pty_get_callbacks(pty);
+ cb->child_sigstop = child_sigstop;
+
+ if (ul_pty_setup(pty))
+ err(EXIT_FAILURE, "failed to create pseudo-terminal");
+
+ fflush(stdout); /* ??? */
+
+ switch ((int) (child = fork())) {
+ case -1: /* error */
+ ul_pty_cleanup(pty);
+ err(EXIT_FAILURE, "cannot create child process");
+ break;
+
+ case 0: /* child */
+ ul_pty_init_slave(pty);
+
+ signal(SIGTERM, SIG_DFL); /* because /etc/csh.login */
+
+ shname = strrchr(shell, '/');
+ shname = shname ? shname + 1 : shell;
+
+ if (command)
+ execl(shell, shname, "-c", command, NULL);
+ else
+ execl(shell, shname, "-i", NULL);
+ err(EXIT_FAILURE, "failed to execute %s", shell);
+ break;
+
+ default:
+ break;
+ }
+
+ /* parent */
+ ul_pty_set_child(pty, child);
+
+ /* this is the main loop */
+ ul_pty_proxy_master(pty);
+
+ /* all done; cleanup and kill */
+ caught_signal = ul_pty_get_delivered_signal(pty);
+
+ if (!caught_signal && ul_pty_get_child(pty) != (pid_t)-1)
+ ul_pty_wait_for_child(pty); /* final wait */
+
+ if (caught_signal && ul_pty_get_child(pty) != (pid_t)-1) {
+ fprintf(stderr, "\nSession terminated, killing shell...");
+ kill(child, SIGTERM);
+ sleep(2);
+ kill(child, SIGKILL);
+ fprintf(stderr, " ...killed.\n");
+ }
+
+ ul_pty_cleanup(pty);
+ ul_free_pty(pty);
+ return EXIT_SUCCESS;
+}
+
+#endif /* TEST_PROGRAM */
+
diff --git a/src/utils/lib/pwdutils.c b/src/utils/lib/pwdutils.c
new file mode 100644
index 0000000..d5f4d2e
--- /dev/null
+++ b/src/utils/lib/pwdutils.c
@@ -0,0 +1,156 @@
+#include <stdlib.h>
+
+#include "c.h"
+#include "pwdutils.h"
+#include "xalloc.h"
+
+/* Returns allocated passwd and allocated pwdbuf to store passwd strings
+ * fields. In case of error returns NULL and set errno, for unknown user set
+ * errno to EINVAL
+ */
+struct passwd *xgetpwnam(const char *username, char **pwdbuf)
+{
+ struct passwd *pwd = NULL, *res = NULL;
+ int rc;
+
+ if (!pwdbuf || !username)
+ return NULL;
+
+ *pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
+ pwd = xcalloc(1, sizeof(struct passwd));
+
+ errno = 0;
+ rc = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+ if (rc != 0) {
+ errno = rc;
+ goto failed;
+ }
+ if (!res) {
+ errno = EINVAL;
+ goto failed;
+ }
+ return pwd;
+failed:
+ free(pwd);
+ free(*pwdbuf);
+ return NULL;
+}
+
+/* Returns allocated group and allocated grpbuf to store group strings
+ * fields. In case of error returns NULL and set errno, for unknown group set
+ * errno to EINVAL
+ */
+struct group *xgetgrnam(const char *groupname, char **grpbuf)
+{
+ struct group *grp = NULL, *res = NULL;
+ int rc;
+
+ if (!grpbuf || !groupname)
+ return NULL;
+
+ *grpbuf = xmalloc(UL_GETPW_BUFSIZ);
+ grp = xcalloc(1, sizeof(struct group));
+
+ errno = 0;
+ rc = getgrnam_r(groupname, grp, *grpbuf, UL_GETPW_BUFSIZ, &res);
+ if (rc != 0) {
+ errno = rc;
+ goto failed;
+ }
+ if (!res) {
+ errno = EINVAL;
+ goto failed;
+ }
+ return grp;
+failed:
+ free(grp);
+ free(*grpbuf);
+ return NULL;
+}
+
+struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
+{
+ struct passwd *pwd = NULL, *res = NULL;
+ int rc;
+
+ if (!pwdbuf)
+ return NULL;
+
+ *pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
+ pwd = xcalloc(1, sizeof(struct passwd));
+
+ errno = 0;
+ rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+ if (rc != 0) {
+ errno = rc;
+ goto failed;
+ }
+ if (!res) {
+ errno = EINVAL;
+ goto failed;
+ }
+ return pwd;
+failed:
+ free(pwd);
+ free(*pwdbuf);
+ return NULL;
+}
+
+char *xgetlogin(void)
+{
+ struct passwd *pw = NULL;
+ uid_t ruid;
+ char *user;
+
+ user = getlogin();
+ if (user)
+ return xstrdup(user);
+
+ /* GNU Hurd implementation has an extension where a process can exist in a
+ * non-conforming environment, and thus be outside the realms of POSIX
+ * process identifiers; on this platform, getuid() fails with a status of
+ * (uid_t)(-1) and sets errno if a program is run from a non-conforming
+ * environment.
+ *
+ * http://austingroupbugs.net/view.php?id=511
+ */
+ errno = 0;
+ ruid = getuid();
+
+ if (errno == 0)
+ pw = getpwuid(ruid);
+ if (pw && pw->pw_name && *pw->pw_name)
+ return xstrdup(pw->pw_name);
+
+ return NULL;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char *argv[])
+{
+ char *buf = NULL;
+ struct passwd *pwd = NULL;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <username>\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ pwd = xgetpwnam(argv[1], &buf);
+ if (!pwd)
+ err(EXIT_FAILURE, "failed to get %s pwd entry", argv[1]);
+
+ printf("Username: %s\n", pwd->pw_name);
+ printf("UID: %d\n", pwd->pw_uid);
+ printf("HOME: %s\n", pwd->pw_dir);
+ printf("GECO: %s\n", pwd->pw_gecos);
+
+ free(pwd);
+ free(buf);
+
+ printf("Current: %s\n", (buf = xgetlogin()));
+ free(buf);
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM */
diff --git a/src/utils/lib/randutils.c b/src/utils/lib/randutils.c
new file mode 100644
index 0000000..bd2a8f6
--- /dev/null
+++ b/src/utils/lib/randutils.c
@@ -0,0 +1,238 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * General purpose random utilities. Based on libuuid code.
+ *
+ * This code is free software; you can redistribute it and/or modify it under
+ * the terms of the Modified BSD License. The complete text of the license is
+ * available in the Documentation/licenses/COPYING.BSD-3-Clause file.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <sys/syscall.h>
+
+#include "c.h"
+#include "randutils.h"
+#include "nls.h"
+
+#ifdef HAVE_TLS
+#define THREAD_LOCAL static __thread
+#else
+#define THREAD_LOCAL static
+#endif
+
+#ifdef HAVE_GETRANDOM
+# include <sys/random.h>
+#elif defined (__linux__)
+# if !defined(SYS_getrandom) && defined(__NR_getrandom)
+ /* usable kernel-headers, but old glibc-headers */
+# define SYS_getrandom __NR_getrandom
+# endif
+#endif
+
+#if !defined(HAVE_GETRANDOM) && defined(SYS_getrandom)
+/* libc without function, but we have syscal */
+#define GRND_NONBLOCK 0x01
+#define GRND_RANDOM 0x02
+static int getrandom(void *buf, size_t buflen, unsigned int flags)
+{
+ return (syscall(SYS_getrandom, buf, buflen, flags));
+}
+# define HAVE_GETRANDOM
+#endif
+
+#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
+#define DO_JRAND_MIX
+THREAD_LOCAL unsigned short ul_jrand_seed[3];
+#endif
+
+int rand_get_number(int low_n, int high_n)
+{
+ return rand() % (high_n - low_n + 1) + low_n;
+}
+
+static void crank_random(void)
+{
+ int i;
+ struct timeval tv;
+ unsigned int n_pid, n_uid;
+
+ gettimeofday(&tv, NULL);
+ n_pid = getpid();
+ n_uid = getuid();
+ srand((n_pid << 16) ^ n_uid ^ tv.tv_sec ^ tv.tv_usec);
+
+#ifdef DO_JRAND_MIX
+ ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
+ ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
+ ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
+#endif
+ /* Crank the random number generator a few times */
+ gettimeofday(&tv, NULL);
+ for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+ rand();
+}
+
+int random_get_fd(void)
+{
+ int i, fd;
+
+ fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (fd >= 0) {
+ i = fcntl(fd, F_GETFD);
+ if (i >= 0)
+ fcntl(fd, F_SETFD, i | FD_CLOEXEC);
+ }
+ crank_random();
+ return fd;
+}
+
+/*
+ * Generate a stream of random nbytes into buf.
+ * Use /dev/urandom if possible, and if not,
+ * use glibc pseudo-random functions.
+ */
+#define UL_RAND_READ_ATTEMPTS 8
+#define UL_RAND_READ_DELAY 125000 /* microseconds */
+
+void random_get_bytes(void *buf, size_t nbytes)
+{
+ unsigned char *cp = (unsigned char *)buf;
+ size_t i, n = nbytes;
+ int lose_counter = 0;
+
+#ifdef HAVE_GETRANDOM
+ while (n > 0) {
+ int x;
+
+ errno = 0;
+ x = getrandom(cp, n, GRND_NONBLOCK);
+ if (x > 0) { /* success */
+ n -= x;
+ cp += x;
+ lose_counter = 0;
+
+ } else if (errno == ENOSYS) { /* kernel without getrandom() */
+ break;
+
+ } else if (errno == EAGAIN && lose_counter < UL_RAND_READ_ATTEMPTS) {
+ xusleep(UL_RAND_READ_DELAY); /* no entropy, wait and try again */
+ lose_counter++;
+ } else
+ break;
+ }
+
+ if (errno == ENOSYS)
+#endif
+ /*
+ * We've been built against headers that support getrandom, but the
+ * running kernel does not. Fallback to reading from /dev/{u,}random
+ * as before
+ */
+ {
+ int fd = random_get_fd();
+
+ lose_counter = 0;
+ if (fd >= 0) {
+ while (n > 0) {
+ ssize_t x = read(fd, cp, n);
+ if (x <= 0) {
+ if (lose_counter++ > UL_RAND_READ_ATTEMPTS)
+ break;
+ xusleep(UL_RAND_READ_DELAY);
+ continue;
+ }
+ n -= x;
+ cp += x;
+ lose_counter = 0;
+ }
+
+ close(fd);
+ }
+ }
+ /*
+ * We do this all the time, but this is the only source of
+ * randomness if /dev/random/urandom is out to lunch.
+ */
+ crank_random();
+ for (cp = buf, i = 0; i < nbytes; i++)
+ *cp++ ^= (rand() >> 7) & 0xFF;
+
+#ifdef DO_JRAND_MIX
+ {
+ unsigned short tmp_seed[3];
+
+ memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed));
+ ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid);
+ for (cp = buf, i = 0; i < nbytes; i++)
+ *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
+ memcpy(ul_jrand_seed, tmp_seed,
+ sizeof(ul_jrand_seed)-sizeof(unsigned short));
+ }
+#endif
+}
+
+
+/*
+ * Tell source of randomness.
+ */
+const char *random_tell_source(void)
+{
+#ifdef HAVE_GETRANDOM
+ return _("getrandom() function");
+#else
+ size_t i;
+ static const char *random_sources[] = {
+ "/dev/urandom",
+ "/dev/random"
+ };
+
+ for (i = 0; i < ARRAY_SIZE(random_sources); i++) {
+ if (!access(random_sources[i], R_OK))
+ return random_sources[i];
+ }
+#endif
+ return _("libc pseudo-random functions");
+}
+
+#ifdef TEST_PROGRAM_RANDUTILS
+#include <inttypes.h>
+
+int main(int argc, char *argv[])
+{
+ size_t i, n;
+ int64_t *vp, v;
+ char *buf;
+ size_t bufsz;
+
+ n = argc == 1 ? 16 : atoi(argv[1]);
+
+ printf("Multiple random calls:\n");
+ for (i = 0; i < n; i++) {
+ random_get_bytes(&v, sizeof(v));
+ printf("#%02zu: %25"PRIu64"\n", i, v);
+ }
+
+
+ printf("One random call:\n");
+ bufsz = n * sizeof(*vp);
+ buf = malloc(bufsz);
+ if (!buf)
+ err(EXIT_FAILURE, "failed to allocate buffer");
+
+ random_get_bytes(buf, bufsz);
+ for (i = 0; i < n; i++) {
+ vp = (int64_t *) (buf + (i * sizeof(*vp)));
+ printf("#%02zu: %25"PRIu64"\n", i, *vp);
+ }
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_RANDUTILS */
diff --git a/src/utils/lib/setproctitle.c b/src/utils/lib/setproctitle.c
new file mode 100644
index 0000000..7168e46
--- /dev/null
+++ b/src/utils/lib/setproctitle.c
@@ -0,0 +1,75 @@
+/*
+ * set process title for ps (from sendmail)
+ *
+ * Clobbers argv of our main procedure so ps(1) will display the title.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "setproctitle.h"
+
+#ifndef SPT_BUFSIZE
+# define SPT_BUFSIZE 2048
+#endif
+
+extern char **environ;
+
+static char **argv0;
+static size_t argv_lth;
+
+void initproctitle (int argc, char **argv)
+{
+ int i;
+ char **envp = environ;
+
+ /*
+ * Move the environment so we can reuse the memory.
+ * (Code borrowed from sendmail.)
+ * WARNING: ugly assumptions on memory layout here;
+ * if this ever causes problems, #undef DO_PS_FIDDLING
+ */
+ for (i = 0; envp[i] != NULL; i++)
+ continue;
+
+ environ = malloc(sizeof(char *) * (i + 1));
+ if (environ == NULL)
+ return;
+
+ for (i = 0; envp[i] != NULL; i++)
+ if ((environ[i] = strdup(envp[i])) == NULL)
+ return;
+ environ[i] = NULL;
+
+ if (i > 0)
+ argv_lth = envp[i-1] + strlen(envp[i-1]) - argv[0];
+ else
+ argv_lth = argv[argc-1] + strlen(argv[argc-1]) - argv[0];
+ if (argv_lth > 1)
+ argv0 = argv;
+}
+
+void setproctitle (const char *prog, const char *txt)
+{
+ size_t i;
+ char buf[SPT_BUFSIZE];
+
+ if (!argv0)
+ return;
+
+ if (strlen(prog) + strlen(txt) + 5 > SPT_BUFSIZE)
+ return;
+
+ sprintf(buf, "%s -- %s", prog, txt);
+
+ i = strlen(buf);
+ if (i > argv_lth - 2) {
+ i = argv_lth - 2;
+ buf[i] = '\0';
+ }
+ memset(argv0[0], '\0', argv_lth); /* clear the memory area */
+ strcpy(argv0[0], buf);
+
+ argv0[1] = NULL;
+}
diff --git a/src/utils/lib/sha1.c b/src/utils/lib/sha1.c
new file mode 100644
index 0000000..22d33b3
--- /dev/null
+++ b/src/utils/lib/sha1.c
@@ -0,0 +1,256 @@
+/*
+ * SHA-1 in C by Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * 1) "abc": A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * 2) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq": 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * 3) A million repetitions of "a": 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+
+#define UL_SHA1HANDSOFF
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "sha1.h"
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+#ifdef WORDS_BIGENDIAN
+# define blk0(i) block->l[i]
+#else
+# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#endif
+
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void ul_SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+ uint32_t a, b, c, d, e;
+
+ typedef union {
+ unsigned char c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+
+#ifdef UL_SHA1HANDSOFF
+ CHAR64LONG16 block[1]; /* use array to appear as a pointer */
+
+ memcpy(block, buffer, 64);
+#else
+ /* The following had better never be used because it causes the
+ * pointer-to-const buffer to be cast into a pointer to non-const.
+ * And the result is written through. I threw a "const" in, hoping
+ * this will cause a diagnostic.
+ */
+ CHAR64LONG16 *block = (const CHAR64LONG16 *)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a, b, c, d, e, 0);
+ R0(e, a, b, c, d, 1);
+ R0(d, e, a, b, c, 2);
+ R0(c, d, e, a, b, 3);
+ R0(b, c, d, e, a, 4);
+ R0(a, b, c, d, e, 5);
+ R0(e, a, b, c, d, 6);
+ R0(d, e, a, b, c, 7);
+ R0(c, d, e, a, b, 8);
+ R0(b, c, d, e, a, 9);
+ R0(a, b, c, d, e, 10);
+ R0(e, a, b, c, d, 11);
+ R0(d, e, a, b, c, 12);
+ R0(c, d, e, a, b, 13);
+ R0(b, c, d, e, a, 14);
+ R0(a, b, c, d, e, 15);
+ R1(e, a, b, c, d, 16);
+ R1(d, e, a, b, c, 17);
+ R1(c, d, e, a, b, 18);
+ R1(b, c, d, e, a, 19);
+ R2(a, b, c, d, e, 20);
+ R2(e, a, b, c, d, 21);
+ R2(d, e, a, b, c, 22);
+ R2(c, d, e, a, b, 23);
+ R2(b, c, d, e, a, 24);
+ R2(a, b, c, d, e, 25);
+ R2(e, a, b, c, d, 26);
+ R2(d, e, a, b, c, 27);
+ R2(c, d, e, a, b, 28);
+ R2(b, c, d, e, a, 29);
+ R2(a, b, c, d, e, 30);
+ R2(e, a, b, c, d, 31);
+ R2(d, e, a, b, c, 32);
+ R2(c, d, e, a, b, 33);
+ R2(b, c, d, e, a, 34);
+ R2(a, b, c, d, e, 35);
+ R2(e, a, b, c, d, 36);
+ R2(d, e, a, b, c, 37);
+ R2(c, d, e, a, b, 38);
+ R2(b, c, d, e, a, 39);
+ R3(a, b, c, d, e, 40);
+ R3(e, a, b, c, d, 41);
+ R3(d, e, a, b, c, 42);
+ R3(c, d, e, a, b, 43);
+ R3(b, c, d, e, a, 44);
+ R3(a, b, c, d, e, 45);
+ R3(e, a, b, c, d, 46);
+ R3(d, e, a, b, c, 47);
+ R3(c, d, e, a, b, 48);
+ R3(b, c, d, e, a, 49);
+ R3(a, b, c, d, e, 50);
+ R3(e, a, b, c, d, 51);
+ R3(d, e, a, b, c, 52);
+ R3(c, d, e, a, b, 53);
+ R3(b, c, d, e, a, 54);
+ R3(a, b, c, d, e, 55);
+ R3(e, a, b, c, d, 56);
+ R3(d, e, a, b, c, 57);
+ R3(c, d, e, a, b, 58);
+ R3(b, c, d, e, a, 59);
+ R4(a, b, c, d, e, 60);
+ R4(e, a, b, c, d, 61);
+ R4(d, e, a, b, c, 62);
+ R4(c, d, e, a, b, 63);
+ R4(b, c, d, e, a, 64);
+ R4(a, b, c, d, e, 65);
+ R4(e, a, b, c, d, 66);
+ R4(d, e, a, b, c, 67);
+ R4(c, d, e, a, b, 68);
+ R4(b, c, d, e, a, 69);
+ R4(a, b, c, d, e, 70);
+ R4(e, a, b, c, d, 71);
+ R4(d, e, a, b, c, 72);
+ R4(c, d, e, a, b, 73);
+ R4(b, c, d, e, a, 74);
+ R4(a, b, c, d, e, 75);
+ R4(e, a, b, c, d, 76);
+ R4(d, e, a, b, c, 77);
+ R4(c, d, e, a, b, 78);
+ R4(b, c, d, e, a, 79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+#ifdef UL_SHA1HANDSOFF
+ memset(block, '\0', sizeof(block));
+#endif
+}
+
+/* SHA1Init - Initialize new context */
+
+void ul_SHA1Init(UL_SHA1_CTX *context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+
+void ul_SHA1Update(UL_SHA1_CTX *context, const unsigned char *data, uint32_t len)
+{
+ uint32_t i;
+
+ uint32_t j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len >> 29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64 - j));
+ ul_SHA1Transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64) {
+ ul_SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+/* Add padding and return the message digest. */
+
+void ul_SHA1Final(unsigned char digest[20], UL_SHA1_CTX *context)
+{
+ unsigned i;
+
+ unsigned char finalcount[8];
+
+ unsigned char c;
+
+#if 0 /* untested "improvement" by DHR */
+ /* Convert context->count to a sequence of bytes
+ * in finalcount. Second element first, but
+ * big-endian order within element.
+ * But we do it all backwards.
+ */
+ unsigned char *fcp = &finalcount[8];
+
+ for (i = 0; i < 2; i++) {
+ uint32_t t = context->count[i];
+
+ int j;
+
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char)t}
+#else
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
+ }
+#endif
+ c = 0200;
+ ul_SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ ul_SHA1Update(context, &c, 1);
+ }
+ ul_SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ /* Wipe variables */
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+
+void ul_SHA1(char *hash_out, const char *str, unsigned len)
+{
+ UL_SHA1_CTX ctx;
+ unsigned int ii;
+
+ ul_SHA1Init(&ctx);
+ for (ii = 0; ii < len; ii += 1)
+ ul_SHA1Update(&ctx, (const unsigned char *)str + ii, 1);
+ ul_SHA1Final((unsigned char *)hash_out, &ctx);
+ hash_out[20] = '\0';
+}
diff --git a/src/utils/lib/signames.c b/src/utils/lib/signames.c
new file mode 100644
index 0000000..316eec5
--- /dev/null
+++ b/src/utils/lib/signames.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1988, 1993, 1994, 2017
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * 2017-10-14 Niklas Hambüchen <mail@nh2.me>
+ * - Extracted signal names mapping from kill.c
+ *
+ * Copyright (C) 2014 Sami Kerola <kerolasa@iki.fi>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2017 Niklas Hambüchen <mail@nh2.me>
+ */
+
+#include <ctype.h> /* for isdigit() */
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "c.h"
+#include "strutils.h"
+#include "signames.h"
+
+static const struct ul_signal_name {
+ const char *name;
+ int val;
+} ul_signames[] = {
+ /* POSIX signals */
+ { "HUP", SIGHUP }, /* 1 */
+ { "INT", SIGINT }, /* 2 */
+ { "QUIT", SIGQUIT }, /* 3 */
+ { "ILL", SIGILL }, /* 4 */
+#ifdef SIGTRAP
+ { "TRAP", SIGTRAP }, /* 5 */
+#endif
+ { "ABRT", SIGABRT }, /* 6 */
+#ifdef SIGIOT
+ { "IOT", SIGIOT }, /* 6, same as SIGABRT */
+#endif
+#ifdef SIGEMT
+ { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
+#endif
+#ifdef SIGBUS
+ { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
+#endif
+ { "FPE", SIGFPE }, /* 8 */
+ { "KILL", SIGKILL }, /* 9 */
+ { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
+ { "SEGV", SIGSEGV }, /* 11 */
+ { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
+ { "PIPE", SIGPIPE }, /* 13 */
+ { "ALRM", SIGALRM }, /* 14 */
+ { "TERM", SIGTERM }, /* 15 */
+#ifdef SIGSTKFLT
+ { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
+#endif
+ { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
+#ifdef SIGCLD
+ { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
+#endif
+ { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
+ { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
+ { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
+ { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
+ { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
+#ifdef SIGURG
+ { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
+#endif
+#ifdef SIGXCPU
+ { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
+#endif
+#ifdef SIGXFSZ
+ { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
+#endif
+#ifdef SIGVTALRM
+ { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
+#endif
+#ifdef SIGPROF
+ { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
+#endif
+#ifdef SIGWINCH
+ { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
+#endif
+#ifdef SIGIO
+ { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
+#endif
+#ifdef SIGPOLL
+ { "POLL", SIGPOLL }, /* same as SIGIO */
+#endif
+#ifdef SIGINFO
+ { "INFO", SIGINFO }, /* 29 (alpha) */
+#endif
+#ifdef SIGLOST
+ { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
+#endif
+#ifdef SIGPWR
+ { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
+#endif
+#ifdef SIGUNUSED
+ { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */
+#endif
+#ifdef SIGSYS
+ { "SYS", SIGSYS }, /* 31 (mips,alpha,sparc*) */
+#endif
+};
+
+#ifdef SIGRTMIN
+static int rtsig_to_signum(const char *sig)
+{
+ int num, maxi = 0;
+ char *ep = NULL;
+
+ if (strncasecmp(sig, "min+", 4) == 0)
+ sig += 4;
+ else if (strncasecmp(sig, "max-", 4) == 0) {
+ sig += 4;
+ maxi = 1;
+ }
+ if (!isdigit(*sig))
+ return -1;
+ errno = 0;
+ num = strtol(sig, &ep, 10);
+ if (!ep || sig == ep || errno || num < 0)
+ return -1;
+ num = maxi ? SIGRTMAX - num : SIGRTMIN + num;
+ if (num < SIGRTMIN || SIGRTMAX < num)
+ return -1;
+ return num;
+}
+#endif
+
+int signame_to_signum(const char *sig)
+{
+ size_t n;
+
+ if (!strncasecmp(sig, "sig", 3))
+ sig += 3;
+#ifdef SIGRTMIN
+ /* RT signals */
+ if (!strncasecmp(sig, "rt", 2))
+ return rtsig_to_signum(sig + 2);
+#endif
+ /* Normal signals */
+ for (n = 0; n < ARRAY_SIZE(ul_signames); n++) {
+ if (!strcasecmp(ul_signames[n].name, sig))
+ return ul_signames[n].val;
+ }
+ return -1;
+}
+
+const char *signum_to_signame(int signum)
+{
+ size_t n;
+
+ for (n = 0; n < ARRAY_SIZE(ul_signames); n++) {
+ if (ul_signames[n].val == signum) {
+ return ul_signames[n].name;
+ }
+ }
+
+ return NULL;
+}
+
+int get_signame_by_idx(size_t idx, const char **signame, int *signum)
+{
+ if (idx >= ARRAY_SIZE(ul_signames))
+ return -1;
+
+ if (signame)
+ *signame = ul_signames[idx].name;
+ if (signum)
+ *signum = ul_signames[idx].val;
+ return 0;
+
+}
+
diff --git a/src/utils/lib/strutils.c b/src/utils/lib/strutils.c
new file mode 100644
index 0000000..304f314
--- /dev/null
+++ b/src/utils/lib/strutils.c
@@ -0,0 +1,1135 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
+ *
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <assert.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+#include "bitops.h"
+#include "pathnames.h"
+
+static int STRTOXX_EXIT_CODE = EXIT_FAILURE;
+
+void strutils_set_exitcode(int ex) {
+ STRTOXX_EXIT_CODE = ex;
+}
+
+static int do_scale_by_power (uintmax_t *x, int base, int power)
+{
+ while (power--) {
+ if (UINTMAX_MAX / base < *x)
+ return -ERANGE;
+ *x *= base;
+ }
+ return 0;
+}
+
+/*
+ * strtosize() - convert string to size (uintmax_t).
+ *
+ * Supported suffixes:
+ *
+ * XiB or X for 2^N
+ * where X = {K,M,G,T,P,E,Z,Y}
+ * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
+ * for example:
+ * 10KiB = 10240
+ * 10K = 10240
+ *
+ * XB for 10^N
+ * where X = {K,M,G,T,P,E,Z,Y}
+ * for example:
+ * 10KB = 10000
+ *
+ * The optional 'power' variable returns number associated with used suffix
+ * {K,M,G,T,P,E,Z,Y} = {1,2,3,4,5,6,7,8}.
+ *
+ * The function also supports decimal point, for example:
+ * 0.5MB = 500000
+ * 0.5MiB = 512000
+ *
+ * Note that the function does not accept numbers with '-' (negative sign)
+ * prefix.
+ */
+int parse_size(const char *str, uintmax_t *res, int *power)
+{
+ const char *p;
+ char *end;
+ uintmax_t x, frac = 0;
+ int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
+
+ static const char *suf = "KMGTPEZY";
+ static const char *suf2 = "kmgtpezy";
+ const char *sp;
+
+ *res = 0;
+
+ if (!str || !*str) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ /* Only positive numbers are acceptable
+ *
+ * Note that this check is not perfect, it would be better to
+ * use lconv->negative_sign. But coreutils use the same solution,
+ * so it's probably good enough...
+ */
+ p = str;
+ while (isspace((unsigned char) *p))
+ p++;
+ if (*p == '-') {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ errno = 0, end = NULL;
+ x = strtoumax(str, &end, 0);
+
+ if (end == str ||
+ (errno != 0 && (x == UINTMAX_MAX || x == 0))) {
+ rc = errno ? -errno : -EINVAL;
+ goto err;
+ }
+ if (!end || !*end)
+ goto done; /* without suffix */
+ p = end;
+
+ /*
+ * Check size suffixes
+ */
+check_suffix:
+ if (*(p + 1) == 'i' && (*(p + 2) == 'B' || *(p + 2) == 'b') && !*(p + 3))
+ base = 1024; /* XiB, 2^N */
+ else if ((*(p + 1) == 'B' || *(p + 1) == 'b') && !*(p + 2))
+ base = 1000; /* XB, 10^N */
+ else if (*(p + 1)) {
+ struct lconv const *l = localeconv();
+ const char *dp = l ? l->decimal_point : NULL;
+ size_t dpsz = dp ? strlen(dp) : 0;
+
+ if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
+ const char *fstr = p + dpsz;
+
+ for (p = fstr; *p == '0'; p++)
+ frac_zeros++;
+ fstr = p;
+ if (isdigit(*fstr)) {
+ errno = 0, end = NULL;
+ frac = strtoumax(fstr, &end, 0);
+ if (end == fstr ||
+ (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
+ rc = errno ? -errno : -EINVAL;
+ goto err;
+ }
+ } else
+ end = (char *) p;
+
+ if (frac && (!end || !*end)) {
+ rc = -EINVAL;
+ goto err; /* without suffix, but with frac */
+ }
+ p = end;
+ goto check_suffix;
+ }
+ rc = -EINVAL;
+ goto err; /* unexpected suffix */
+ }
+
+ sp = strchr(suf, *p);
+ if (sp)
+ pwr = (sp - suf) + 1;
+ else {
+ sp = strchr(suf2, *p);
+ if (sp)
+ pwr = (sp - suf2) + 1;
+ else {
+ rc = -EINVAL;
+ goto err;
+ }
+ }
+
+ rc = do_scale_by_power(&x, base, pwr);
+ if (power)
+ *power = pwr;
+ if (frac && pwr) {
+ int i;
+ uintmax_t frac_div = 10, frac_poz = 1, frac_base = 1;
+
+ /* mega, giga, ... */
+ do_scale_by_power(&frac_base, base, pwr);
+
+ /* maximal divisor for last digit (e.g. for 0.05 is
+ * frac_div=100, for 0.054 is frac_div=1000, etc.)
+ *
+ * Reduce frac if too large.
+ */
+ while (frac_div < frac) {
+ if (frac_div <= UINTMAX_MAX/10)
+ frac_div *= 10;
+ else
+ frac /= 10;
+ }
+
+ /* 'frac' is without zeros (5 means 0.5 as well as 0.05) */
+ for (i = 0; i < frac_zeros; i++) {
+ if (frac_div <= UINTMAX_MAX/10)
+ frac_div *= 10;
+ else
+ frac /= 10;
+ }
+
+ /*
+ * Go backwardly from last digit and add to result what the
+ * digit represents in the frac_base. For example 0.25G
+ *
+ * 5 means 1GiB / (100/5)
+ * 2 means 1GiB / (10/2)
+ */
+ do {
+ unsigned int seg = frac % 10; /* last digit of the frac */
+ uintmax_t seg_div = frac_div / frac_poz; /* what represents the segment 1000, 100, .. */
+
+ frac /= 10; /* remove last digit from frac */
+ frac_poz *= 10;
+
+ if (seg && seg_div / seg)
+ x += frac_base / (seg_div / seg);
+ } while (frac);
+ }
+done:
+ *res = x;
+err:
+ if (rc < 0)
+ errno = -rc;
+ return rc;
+}
+
+int strtosize(const char *str, uintmax_t *res)
+{
+ return parse_size(str, res, NULL);
+}
+
+int isdigit_strend(const char *str, const char **end)
+{
+ const char *p;
+
+ for (p = str; p && *p && isdigit((unsigned char) *p); p++);
+
+ if (end)
+ *end = p;
+ return p && p > str && !*p;
+}
+
+int isxdigit_strend(const char *str, const char **end)
+{
+ const char *p;
+
+ for (p = str; p && *p && isxdigit((unsigned char) *p); p++);
+
+ if (end)
+ *end = p;
+
+ return p && p > str && !*p;
+}
+
+/*
+ * parse_switch(argv[i], "on", "off", "yes", "no", NULL);
+ */
+int parse_switch(const char *arg, const char *errmesg, ...)
+{
+ const char *a, *b;
+ va_list ap;
+
+ va_start(ap, errmesg);
+ do {
+ a = va_arg(ap, char *);
+ if (!a)
+ break;
+ b = va_arg(ap, char *);
+ if (!b)
+ break;
+
+ if (strcmp(arg, a) == 0) {
+ va_end(ap);
+ return 1;
+ }
+
+ if (strcmp(arg, b) == 0) {
+ va_end(ap);
+ return 0;
+ }
+ } while (1);
+ va_end(ap);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, arg);
+}
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
+{
+ return ((char *)memcpy(dest, src, n)) + n;
+}
+#endif
+
+#ifndef HAVE_STRNLEN
+size_t strnlen(const char *s, size_t maxlen)
+{
+ size_t i;
+
+ for (i = 0; i < maxlen; i++) {
+ if (s[i] == '\0')
+ return i;
+ }
+ return maxlen;
+}
+#endif
+
+#ifndef HAVE_STRNCHR
+char *strnchr(const char *s, size_t maxlen, int c)
+{
+ for (; maxlen-- && *s != '\0'; ++s)
+ if (*s == (char)c)
+ return (char *)s;
+ return NULL;
+}
+#endif
+
+#ifndef HAVE_STRNDUP
+char *strndup(const char *s, size_t n)
+{
+ size_t len = strnlen(s, n);
+ char *new = malloc((len + 1) * sizeof(char));
+ if (!new)
+ return NULL;
+ new[len] = '\0';
+ return (char *) memcpy(new, s, len);
+}
+#endif
+
+static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base);
+static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base);
+
+int16_t strtos16_or_err(const char *str, const char *errmesg)
+{
+ int32_t num = strtos32_or_err(str, errmesg);
+
+ if (num < INT16_MIN || num > INT16_MAX) {
+ errno = ERANGE;
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ return num;
+}
+
+static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base)
+{
+ uint32_t num = _strtou32_or_err(str, errmesg, base);
+
+ if (num > UINT16_MAX) {
+ errno = ERANGE;
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ return num;
+}
+
+uint16_t strtou16_or_err(const char *str, const char *errmesg)
+{
+ return _strtou16_or_err(str, errmesg, 10);
+}
+
+uint16_t strtox16_or_err(const char *str, const char *errmesg)
+{
+ return _strtou16_or_err(str, errmesg, 16);
+}
+
+int32_t strtos32_or_err(const char *str, const char *errmesg)
+{
+ int64_t num = strtos64_or_err(str, errmesg);
+
+ if (num < INT32_MIN || num > INT32_MAX) {
+ errno = ERANGE;
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ return num;
+}
+
+static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base)
+{
+ uint64_t num = _strtou64_or_err(str, errmesg, base);
+
+ if (num > UINT32_MAX) {
+ errno = ERANGE;
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+ }
+ return num;
+}
+
+uint32_t strtou32_or_err(const char *str, const char *errmesg)
+{
+ return _strtou32_or_err(str, errmesg, 10);
+}
+
+uint32_t strtox32_or_err(const char *str, const char *errmesg)
+{
+ return _strtou32_or_err(str, errmesg, 16);
+}
+
+int64_t strtos64_or_err(const char *str, const char *errmesg)
+{
+ int64_t num;
+ char *end = NULL;
+
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ goto err;
+ num = strtoimax(str, &end, 10);
+
+ if (errno || str == end || (end && *end))
+ goto err;
+
+ return num;
+err:
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base)
+{
+ uintmax_t num;
+ char *end = NULL;
+
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ goto err;
+ num = strtoumax(str, &end, base);
+
+ if (errno || str == end || (end && *end))
+ goto err;
+
+ return num;
+err:
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+uint64_t strtou64_or_err(const char *str, const char *errmesg)
+{
+ return _strtou64_or_err(str, errmesg, 10);
+}
+
+uint64_t strtox64_or_err(const char *str, const char *errmesg)
+{
+ return _strtou64_or_err(str, errmesg, 16);
+}
+
+double strtod_or_err(const char *str, const char *errmesg)
+{
+ double num;
+ char *end = NULL;
+
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ goto err;
+ num = strtod(str, &end);
+
+ if (errno || str == end || (end && *end))
+ goto err;
+
+ return num;
+err:
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+long strtol_or_err(const char *str, const char *errmesg)
+{
+ long num;
+ char *end = NULL;
+
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ goto err;
+ num = strtol(str, &end, 10);
+
+ if (errno || str == end || (end && *end))
+ goto err;
+
+ return num;
+err:
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+unsigned long strtoul_or_err(const char *str, const char *errmesg)
+{
+ unsigned long num;
+ char *end = NULL;
+
+ errno = 0;
+ if (str == NULL || *str == '\0')
+ goto err;
+ num = strtoul(str, &end, 10);
+
+ if (errno || str == end || (end && *end))
+ goto err;
+
+ return num;
+err:
+ if (errno == ERANGE)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+uintmax_t strtosize_or_err(const char *str, const char *errmesg)
+{
+ uintmax_t num;
+
+ if (strtosize(str, &num) == 0)
+ return num;
+
+ if (errno)
+ err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+
+ errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
+}
+
+
+void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
+{
+ double user_input;
+
+ user_input = strtod_or_err(str, errmesg);
+ tv->tv_sec = (time_t) user_input;
+ tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
+}
+
+/*
+ * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
+ * be 11 bytes.
+ */
+char *xstrmode(mode_t mode, char *str)
+{
+ unsigned short i = 0;
+
+ if (S_ISDIR(mode))
+ str[i++] = 'd';
+ else if (S_ISLNK(mode))
+ str[i++] = 'l';
+ else if (S_ISCHR(mode))
+ str[i++] = 'c';
+ else if (S_ISBLK(mode))
+ str[i++] = 'b';
+ else if (S_ISSOCK(mode))
+ str[i++] = 's';
+ else if (S_ISFIFO(mode))
+ str[i++] = 'p';
+ else if (S_ISREG(mode))
+ str[i++] = '-';
+
+ str[i++] = mode & S_IRUSR ? 'r' : '-';
+ str[i++] = mode & S_IWUSR ? 'w' : '-';
+ str[i++] = (mode & S_ISUID
+ ? (mode & S_IXUSR ? 's' : 'S')
+ : (mode & S_IXUSR ? 'x' : '-'));
+ str[i++] = mode & S_IRGRP ? 'r' : '-';
+ str[i++] = mode & S_IWGRP ? 'w' : '-';
+ str[i++] = (mode & S_ISGID
+ ? (mode & S_IXGRP ? 's' : 'S')
+ : (mode & S_IXGRP ? 'x' : '-'));
+ str[i++] = mode & S_IROTH ? 'r' : '-';
+ str[i++] = mode & S_IWOTH ? 'w' : '-';
+ str[i++] = (mode & S_ISVTX
+ ? (mode & S_IXOTH ? 't' : 'T')
+ : (mode & S_IXOTH ? 'x' : '-'));
+ str[i] = '\0';
+
+ return str;
+}
+
+/*
+ * returns exponent (2^x=n) in range KiB..EiB (2^10..2^60)
+ */
+static int get_exp(uint64_t n)
+{
+ int shft;
+
+ for (shft = 10; shft <= 60; shft += 10) {
+ if (n < (1ULL << shft))
+ break;
+ }
+ return shft - 10;
+}
+
+char *size_to_human_string(int options, uint64_t bytes)
+{
+ char buf[32];
+ int dec, exp;
+ uint64_t frac;
+ const char *letters = "BKMGTPE";
+ char suffix[sizeof(" KiB")], *psuf = suffix;
+ char c;
+
+ if (options & SIZE_SUFFIX_SPACE)
+ *psuf++ = ' ';
+
+
+ exp = get_exp(bytes);
+ c = *(letters + (exp ? exp / 10 : 0));
+ dec = exp ? bytes / (1ULL << exp) : bytes;
+ frac = exp ? bytes % (1ULL << exp) : 0;
+
+ *psuf++ = c;
+
+ if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
+ *psuf++ = 'i';
+ *psuf++ = 'B';
+ }
+
+ *psuf = '\0';
+
+ /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n",
+ * exp, suffix[0], dec, frac);
+ */
+
+ /* round */
+ if (frac) {
+ /* get 3 digits after decimal point */
+ if (frac >= UINT64_MAX / 1000)
+ frac = ((frac / 1024) * 1000) / (1ULL << (exp - 10)) ;
+ else
+ frac = (frac * 1000) / (1ULL << (exp)) ;
+
+ if (options & SIZE_DECIMAL_2DIGITS) {
+ /* round 4/5 and keep 2 digits after decimal point */
+ frac = (frac + 5) / 10 ;
+ } else {
+ /* round 4/5 and keep 1 digit after decimal point */
+ frac = ((frac + 50) / 100) * 10 ;
+ }
+
+ /* rounding could have overflowed */
+ if (frac == 100) {
+ dec++;
+ frac = 0;
+ }
+ }
+
+ if (frac) {
+ struct lconv const *l = localeconv();
+ char *dp = l ? l->decimal_point : NULL;
+ int len;
+
+ if (!dp || !*dp)
+ dp = ".";
+
+ len = snprintf(buf, sizeof(buf), "%d%s%02" PRIu64, dec, dp, frac);
+ if (len > 0 && (size_t) len < sizeof(buf)) {
+ /* remove potential extraneous zero */
+ if (buf[len - 1] == '0')
+ buf[len--] = '\0';
+ /* append suffix */
+ xstrncpy(buf+len, suffix, sizeof(buf) - len);
+ } else
+ *buf = '\0'; /* snprintf error */
+ } else
+ snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
+
+ return strdup(buf);
+}
+
+/*
+ * Parses comma delimited list to array with IDs, for example:
+ *
+ * "aaa,bbb,ccc" --> ary[0] = FOO_AAA;
+ * ary[1] = FOO_BBB;
+ * ary[3] = FOO_CCC;
+ *
+ * The function name2id() provides conversion from string to ID.
+ *
+ * Returns: >= 0 : number of items added to ary[]
+ * -1 : parse error or unknown item
+ * -2 : arysz reached
+ */
+int string_to_idarray(const char *list, int ary[], size_t arysz,
+ int (name2id)(const char *, size_t))
+{
+ const char *begin = NULL, *p;
+ size_t n = 0;
+
+ if (!list || !*list || !ary || !arysz || !name2id)
+ return -1;
+
+ for (p = list; p && *p; p++) {
+ const char *end = NULL;
+ int id;
+
+ if (n >= arysz)
+ return -2;
+ if (!begin)
+ begin = p; /* begin of the column name */
+ if (*p == ',')
+ end = p; /* terminate the name */
+ if (*(p + 1) == '\0')
+ end = p + 1; /* end of string */
+ if (!begin || !end)
+ continue;
+ if (end <= begin)
+ return -1;
+
+ id = name2id(begin, end - begin);
+ if (id == -1)
+ return -1;
+ ary[ n++ ] = id;
+ begin = NULL;
+ if (end && !*end)
+ break;
+ }
+ return n;
+}
+
+/*
+ * Parses the array like string_to_idarray but if format is "+aaa,bbb"
+ * it adds fields to array instead of replacing them.
+ */
+int string_add_to_idarray(const char *list, int ary[], size_t arysz,
+ size_t *ary_pos, int (name2id)(const char *, size_t))
+{
+ const char *list_add;
+ int r;
+
+ if (!list || !*list || !ary_pos || *ary_pos > arysz)
+ return -1;
+
+ if (list[0] == '+')
+ list_add = &list[1];
+ else {
+ list_add = list;
+ *ary_pos = 0;
+ }
+
+ r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id);
+ if (r > 0)
+ *ary_pos += r;
+ return r;
+}
+
+/*
+ * LIST ::= <item> [, <item>]
+ *
+ * The <item> is translated to 'id' by name2id() function and the 'id' is used
+ * as a position in the 'ary' bit array. It means that the 'id' has to be in
+ * range <0..N> where N < sizeof(ary) * NBBY.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int string_to_bitarray(const char *list,
+ char *ary,
+ int (*name2bit)(const char *, size_t))
+{
+ const char *begin = NULL, *p;
+
+ if (!list || !name2bit || !ary)
+ return -EINVAL;
+
+ for (p = list; p && *p; p++) {
+ const char *end = NULL;
+ int bit;
+
+ if (!begin)
+ begin = p; /* begin of the level name */
+ if (*p == ',')
+ end = p; /* terminate the name */
+ if (*(p + 1) == '\0')
+ end = p + 1; /* end of string */
+ if (!begin || !end)
+ continue;
+ if (end <= begin)
+ return -1;
+
+ bit = name2bit(begin, end - begin);
+ if (bit < 0)
+ return bit;
+ setbit(ary, bit);
+ begin = NULL;
+ if (end && !*end)
+ break;
+ }
+ return 0;
+}
+
+/*
+ * LIST ::= <item> [, <item>]
+ *
+ * The <item> is translated to 'id' by name2flag() function and the flags is
+ * set to the 'mask'
+*
+ * Returns: 0 on success, <0 on error.
+ */
+int string_to_bitmask(const char *list,
+ unsigned long *mask,
+ long (*name2flag)(const char *, size_t))
+{
+ const char *begin = NULL, *p;
+
+ if (!list || !name2flag || !mask)
+ return -EINVAL;
+
+ for (p = list; p && *p; p++) {
+ const char *end = NULL;
+ long flag;
+
+ if (!begin)
+ begin = p; /* begin of the level name */
+ if (*p == ',')
+ end = p; /* terminate the name */
+ if (*(p + 1) == '\0')
+ end = p + 1; /* end of string */
+ if (!begin || !end)
+ continue;
+ if (end <= begin)
+ return -1;
+
+ flag = name2flag(begin, end - begin);
+ if (flag < 0)
+ return flag; /* error */
+ *mask |= flag;
+ begin = NULL;
+ if (end && !*end)
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Parse the lower and higher values in a string containing
+ * "lower:higher" or "lower-higher" format. Note that either
+ * the lower or the higher values may be missing, and the def
+ * value will be assigned to it by default.
+ *
+ * Returns: 0 on success, <0 on error.
+ */
+int parse_range(const char *str, int *lower, int *upper, int def)
+{
+ char *end = NULL;
+
+ if (!str)
+ return 0;
+
+ *upper = *lower = def;
+ errno = 0;
+
+ if (*str == ':') { /* <:N> */
+ str++;
+ *upper = strtol(str, &end, 10);
+ if (errno || !end || *end || end == str)
+ return -1;
+ } else {
+ *upper = *lower = strtol(str, &end, 10);
+ if (errno || !end || end == str)
+ return -1;
+
+ if (*end == ':' && !*(end + 1)) /* <M:> */
+ *upper = def;
+ else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
+ str = end + 1;
+ end = NULL;
+ errno = 0;
+ *upper = strtol(str, &end, 10);
+
+ if (errno || !end || *end || end == str)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static const char *next_path_segment(const char *str, size_t *sz)
+{
+ const char *start, *p;
+
+ start = str;
+ *sz = 0;
+ while (start && *start == '/' && *(start + 1) == '/')
+ start++;
+
+ if (!start || !*start)
+ return NULL;
+
+ for (*sz = 1, p = start + 1; *p && *p != '/'; p++) {
+ (*sz)++;
+ }
+
+ return start;
+}
+
+int streq_paths(const char *a, const char *b)
+{
+ while (a && b) {
+ size_t a_sz, b_sz;
+ const char *a_seg = next_path_segment(a, &a_sz);
+ const char *b_seg = next_path_segment(b, &b_sz);
+
+ /*
+ fprintf(stderr, "A>>>(%zu) '%s'\n", a_sz, a_seg);
+ fprintf(stderr, "B>>>(%zu) '%s'\n", b_sz, b_seg);
+ */
+
+ /* end of the path */
+ if (a_sz + b_sz == 0)
+ return 1;
+
+ /* ignore tailing slash */
+ if (a_sz + b_sz == 1 &&
+ ((a_seg && *a_seg == '/') || (b_seg && *b_seg == '/')))
+ return 1;
+
+ if (!a_seg || !b_seg)
+ break;
+ if (a_sz != b_sz || strncmp(a_seg, b_seg, a_sz) != 0)
+ break;
+
+ a = a_seg + a_sz;
+ b = b_seg + b_sz;
+ };
+
+ return 0;
+}
+
+char *strnappend(const char *s, const char *suffix, size_t b)
+{
+ size_t a;
+ char *r;
+
+ if (!s && !suffix)
+ return strdup("");
+ if (!s)
+ return strndup(suffix, b);
+ if (!suffix)
+ return strdup(s);
+
+ assert(s);
+ assert(suffix);
+
+ a = strlen(s);
+ if (b > ((size_t) -1) - a)
+ return NULL;
+
+ r = malloc(a + b + 1);
+ if (!r)
+ return NULL;
+
+ memcpy(r, s, a);
+ memcpy(r + a, suffix, b);
+ r[a+b] = 0;
+
+ return r;
+}
+
+char *strappend(const char *s, const char *suffix)
+{
+ return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+char *strfappend(const char *s, const char *format, ...)
+{
+ va_list ap;
+ char *val, *res;
+ int sz;
+
+ va_start(ap, format);
+ sz = vasprintf(&val, format, ap);
+ va_end(ap);
+
+ if (sz < 0)
+ return NULL;
+
+ res = strnappend(s, val, sz);
+ free(val);
+ return res;
+}
+
+static size_t strcspn_escaped(const char *s, const char *reject)
+{
+ int escaped = 0;
+ int n;
+
+ for (n=0; s[n]; n++) {
+ if (escaped)
+ escaped = 0;
+ else if (s[n] == '\\')
+ escaped = 1;
+ else if (strchr(reject, s[n]))
+ break;
+ }
+
+ /* if s ends in \, return index of previous char */
+ return n - escaped;
+}
+
+/* Split a string into words. */
+const char *split(const char **state, size_t *l, const char *separator, int quoted)
+{
+ const char *current;
+
+ current = *state;
+
+ if (!*current) {
+ assert(**state == '\0');
+ return NULL;
+ }
+
+ current += strspn(current, separator);
+ if (!*current) {
+ *state = current;
+ return NULL;
+ }
+
+ if (quoted && strchr("\'\"", *current)) {
+ char quotechars[2] = {*current, '\0'};
+
+ *l = strcspn_escaped(current + 1, quotechars);
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+ (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+ /* right quote missing or garbage at the end */
+ *state = current;
+ return NULL;
+ }
+ *state = current++ + *l + 2;
+ } else if (quoted) {
+ *l = strcspn_escaped(current, separator);
+ if (current[*l] && !strchr(separator, current[*l])) {
+ /* unfinished escape */
+ *state = current;
+ return NULL;
+ }
+ *state = current + *l;
+ } else {
+ *l = strcspn(current, separator);
+ *state = current + *l;
+ }
+
+ return current;
+}
+
+/* Rewind file pointer forward to new line. */
+int skip_fline(FILE *fp)
+{
+ int ch;
+
+ do {
+ if ((ch = fgetc(fp)) == EOF)
+ return 1;
+ if (ch == '\n')
+ return 0;
+ } while (1);
+}
+
+#ifdef TEST_PROGRAM_STRUTILS
+struct testS {
+ char *name;
+ char *value;
+};
+
+static int test_strdup_to_member(int argc, char *argv[])
+{
+ struct testS *xx;
+
+ if (argc < 3)
+ return EXIT_FAILURE;
+
+ xx = calloc(1, sizeof(*xx));
+ if (!xx)
+ err(EXIT_FAILURE, "calloc() failed");
+
+ strdup_to_struct_member(xx, name, argv[1]);
+ strdup_to_struct_member(xx, value, argv[2]);
+
+ if (strcmp(xx->name, argv[1]) != 0 &&
+ strcmp(xx->value, argv[2]) != 0)
+ errx(EXIT_FAILURE, "strdup_to_struct_member() failed");
+
+ printf("1: '%s', 2: '%s'\n", xx->name, xx->value);
+
+ free(xx->name);
+ free(xx->value);
+ free(xx);
+ return EXIT_SUCCESS;
+}
+
+static int test_strutils_sizes(int argc, char *argv[])
+{
+ uintmax_t size = 0;
+ char *hum1, *hum2, *hum3;
+
+ if (argc < 2)
+ return EXIT_FAILURE;
+
+ if (strtosize(argv[1], &size))
+ errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
+
+ hum1 = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
+ hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER |
+ SIZE_SUFFIX_SPACE, size);
+ hum3 = size_to_human_string(SIZE_SUFFIX_3LETTER |
+ SIZE_SUFFIX_SPACE |
+ SIZE_DECIMAL_2DIGITS, size);
+
+ printf("%25s : %20ju : %8s : %12s : %13s\n", argv[1], size, hum1, hum2, hum3);
+ free(hum1);
+ free(hum2);
+ free(hum3);
+
+ return EXIT_SUCCESS;
+}
+
+static int test_strutils_cmp_paths(int argc, char *argv[])
+{
+ int rc = streq_paths(argv[1], argv[2]);
+
+ if (argc < 3)
+ return EXIT_FAILURE;
+
+ printf("%s: '%s' '%s'\n", rc == 1 ? "YES" : "NOT", argv[1], argv[2]);
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc == 3 && strcmp(argv[1], "--size") == 0)
+ return test_strutils_sizes(argc - 1, argv + 1);
+
+ if (argc == 4 && strcmp(argv[1], "--cmp-paths") == 0)
+ return test_strutils_cmp_paths(argc - 1, argv + 1);
+
+ if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0)
+ return test_strdup_to_member(argc - 1, argv + 1);
+
+ fprintf(stderr, "usage: %1$s --size <number>[suffix]\n"
+ " %1$s --cmp-paths <path> <path>\n"
+ " %1$s --strdup-member <str> <str>\n",
+ argv[0]);
+
+ return EXIT_FAILURE;
+}
+#endif /* TEST_PROGRAM_STRUTILS */
diff --git a/src/utils/lib/strv.c b/src/utils/lib/strv.c
new file mode 100644
index 0000000..ddc2a0c
--- /dev/null
+++ b/src/utils/lib/strv.c
@@ -0,0 +1,403 @@
+/*
+ *
+ * Copyright 2010 Lennart Poettering
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ * Copyright (C) 2015 Karel Zak <kzak@redhat.com>
+ * Modified the original version from systemd project for util-linux.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "strutils.h"
+#include "strv.h"
+
+void strv_clear(char **l) {
+ char **k;
+
+ if (!l)
+ return;
+
+ for (k = l; *k; k++)
+ free(*k);
+
+ *l = NULL;
+}
+
+char **strv_free(char **l) {
+ strv_clear(l);
+ free(l);
+ return NULL;
+}
+
+char **strv_copy(char * const *l) {
+ char **r, **k;
+
+ k = r = malloc(sizeof(char *) * (strv_length(l) + 1));
+ if (!r)
+ return NULL;
+
+ if (l)
+ for (; *l; k++, l++) {
+ *k = strdup(*l);
+ if (!*k) {
+ strv_free(r);
+ return NULL;
+ }
+ }
+
+ *k = NULL;
+ return r;
+}
+
+unsigned strv_length(char * const *l) {
+ unsigned n = 0;
+
+ if (!l)
+ return 0;
+
+ for (; *l; l++)
+ n++;
+
+ return n;
+}
+
+char **strv_new_ap(const char *x, va_list ap) {
+ const char *s;
+ char **a;
+ unsigned n = 0, i = 0;
+ va_list aq;
+
+ /* As a special trick we ignore all listed strings that equal
+ * (const char*) -1. This is supposed to be used with the
+ * STRV_IFNOTNULL() macro to include possibly NULL strings in
+ * the string list. */
+
+ if (x) {
+ n = x == (const char*) -1 ? 0 : 1;
+
+ va_copy(aq, ap);
+ while ((s = va_arg(aq, const char*))) {
+ if (s == (const char*) -1)
+ continue;
+
+ n++;
+ }
+
+ va_end(aq);
+ }
+
+ a = malloc(sizeof(char *) * (n + 1));
+ if (!a)
+ return NULL;
+
+ if (x) {
+ if (x != (const char*) -1) {
+ a[i] = strdup(x);
+ if (!a[i])
+ goto fail;
+ i++;
+ }
+
+ while ((s = va_arg(ap, const char*))) {
+
+ if (s == (const char*) -1)
+ continue;
+
+ a[i] = strdup(s);
+ if (!a[i])
+ goto fail;
+
+ i++;
+ }
+ }
+
+ a[i] = NULL;
+
+ return a;
+
+fail:
+ strv_free(a);
+ return NULL;
+}
+
+char **strv_new(const char *x, ...) {
+ char **r;
+ va_list ap;
+
+ va_start(ap, x);
+ r = strv_new_ap(x, ap);
+ va_end(ap);
+
+ return r;
+}
+
+int strv_extend_strv(char ***a, char **b) {
+ int r;
+ char **s;
+
+ STRV_FOREACH(s, b) {
+ r = strv_extend(a, *s);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
+ int r;
+ char **s;
+
+ STRV_FOREACH(s, b) {
+ char *v;
+
+ v = strappend(*s, suffix);
+ if (!v)
+ return -ENOMEM;
+
+ r = strv_push(a, v);
+ if (r < 0) {
+ free(v);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+
+#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
+ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
+ _FOREACH_WORD(word, length, s, separator, false, state)
+
+
+char **strv_split(const char *s, const char *separator) {
+ const char *word, *state;
+ size_t l;
+ unsigned n, i;
+ char **r;
+
+ assert(s);
+
+ n = 0;
+ FOREACH_WORD_SEPARATOR(word, l, s, separator, state)
+ n++;
+
+ r = malloc(sizeof(char *) * (n + 1));
+ if (!r)
+ return NULL;
+
+ i = 0;
+ FOREACH_WORD_SEPARATOR(word, l, s, separator, state) {
+ r[i] = strndup(word, l);
+ if (!r[i]) {
+ strv_free(r);
+ return NULL;
+ }
+
+ i++;
+ }
+
+ r[i] = NULL;
+ return r;
+}
+
+char *strv_join(char **l, const char *separator) {
+ char *r, *e;
+ char **s;
+ size_t n, k;
+
+ if (!separator)
+ separator = " ";
+
+ k = strlen(separator);
+
+ n = 0;
+ STRV_FOREACH(s, l) {
+ if (n != 0)
+ n += k;
+ n += strlen(*s);
+ }
+
+ r = malloc(n + 1);
+ if (!r)
+ return NULL;
+
+ e = r;
+ STRV_FOREACH(s, l) {
+ if (e != r)
+ e = stpcpy(e, separator);
+
+ e = stpcpy(e, *s);
+ }
+
+ *e = 0;
+
+ return r;
+}
+
+int strv_push(char ***l, char *value) {
+ char **c;
+ unsigned n, m;
+
+ if (!value)
+ return 0;
+
+ n = strv_length(*l);
+
+ /* Increase and check for overflow */
+ m = n + 2;
+ if (m < n)
+ return -ENOMEM;
+
+ c = realloc(*l, sizeof(char *) * m);
+ if (!c)
+ return -ENOMEM;
+
+ c[n] = value;
+ c[n+1] = NULL;
+
+ *l = c;
+ return 0;
+}
+
+int strv_push_prepend(char ***l, char *value) {
+ char **c;
+ unsigned n, m, i;
+
+ if (!value)
+ return 0;
+
+ n = strv_length(*l);
+
+ /* increase and check for overflow */
+ m = n + 2;
+ if (m < n)
+ return -ENOMEM;
+
+ c = malloc(sizeof(char *) * m);
+ if (!c)
+ return -ENOMEM;
+
+ for (i = 0; i < n; i++)
+ c[i+1] = (*l)[i];
+
+ c[0] = value;
+ c[n+1] = NULL;
+
+ free(*l);
+ *l = c;
+
+ return 0;
+}
+
+int strv_consume(char ***l, char *value) {
+ int r;
+
+ r = strv_push(l, value);
+ if (r < 0)
+ free(value);
+
+ return r;
+}
+
+int strv_consume_prepend(char ***l, char *value) {
+ int r;
+
+ r = strv_push_prepend(l, value);
+ if (r < 0)
+ free(value);
+
+ return r;
+}
+
+int strv_extend(char ***l, const char *value) {
+ char *v;
+
+ if (!value)
+ return 0;
+
+ v = strdup(value);
+ if (!v)
+ return -ENOMEM;
+
+ return strv_consume(l, v);
+}
+
+char **strv_remove(char **l, const char *s) {
+ char **f, **t;
+
+ if (!l)
+ return NULL;
+
+ assert(s);
+
+ /* Drops every occurrence of s in the string list, edits
+ * in-place. */
+
+ for (f = t = l; *f; f++)
+ if (strcmp(*f, s) == 0)
+ free(*f);
+ else
+ *(t++) = *f;
+
+ *t = NULL;
+ return l;
+}
+
+int strv_extendf(char ***l, const char *format, ...) {
+ va_list ap;
+ char *x;
+ int r;
+
+ va_start(ap, format);
+ r = vasprintf(&x, format, ap);
+ va_end(ap);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ return strv_consume(l, x);
+}
+
+int strv_extendv(char ***l, const char *format, va_list ap) {
+ char *x;
+ int r;
+
+ r = vasprintf(&x, format, ap);
+ if (r < 0)
+ return -ENOMEM;
+
+ return strv_consume(l, x);
+}
+
+char **strv_reverse(char **l) {
+ unsigned n, i;
+
+ n = strv_length(l);
+ if (n <= 1)
+ return l;
+
+ for (i = 0; i < n / 2; i++) {
+ char *t;
+
+ t = l[i];
+ l[i] = l[n-1-i];
+ l[n-1-i] = t;
+ }
+
+ return l;
+}
diff --git a/src/utils/lib/sysfs.c b/src/utils/lib/sysfs.c
new file mode 100644
index 0000000..5b4de2c
--- /dev/null
+++ b/src/utils/lib/sysfs.c
@@ -0,0 +1,1127 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include <ctype.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "c.h"
+#include "pathnames.h"
+#include "sysfs.h"
+#include "fileutils.h"
+#include "all-io.h"
+#include "debug.h"
+#include "strutils.h"
+
+static void sysfs_blkdev_deinit_path(struct path_cxt *pc);
+static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd);
+
+/*
+ * Debug stuff (based on include/debug.h)
+ */
+static UL_DEBUG_DEFINE_MASK(ulsysfs);
+UL_DEBUG_DEFINE_MASKNAMES(ulsysfs) = UL_DEBUG_EMPTY_MASKNAMES;
+
+#define ULSYSFS_DEBUG_INIT (1 << 1)
+#define ULSYSFS_DEBUG_CXT (1 << 2)
+
+#define DBG(m, x) __UL_DBG(ulsysfs, ULSYSFS_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(ulsysfs, ULSYSFS_DEBUG_, m, x)
+
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulsysfs)
+#include "debugobj.h"
+
+void ul_sysfs_init_debug(void)
+{
+ if (ulsysfs_debug_mask)
+ return;
+ __UL_INIT_DEBUG_FROM_ENV(ulsysfs, ULSYSFS_DEBUG_, 0, ULSYSFS_DEBUG);
+}
+
+struct path_cxt *ul_new_sysfs_path(dev_t devno, struct path_cxt *parent, const char *prefix)
+{
+ struct path_cxt *pc = ul_new_path(NULL);
+
+ if (!pc)
+ return NULL;
+ if (prefix)
+ ul_path_set_prefix(pc, prefix);
+
+ if (sysfs_blkdev_init_path(pc, devno, parent) != 0) {
+ ul_unref_path(pc);
+ return NULL;
+ }
+
+ DBG(CXT, ul_debugobj(pc, "alloc"));
+ return pc;
+}
+
+/*
+ * sysfs_blkdev_* is sysfs extension to ul_path_* API for block devices.
+ *
+ * The function is possible to call in loop and without sysfs_blkdev_deinit_path().
+ * The sysfs_blkdev_deinit_path() is automatically called by ul_unref_path().
+ *
+ */
+int sysfs_blkdev_init_path(struct path_cxt *pc, dev_t devno, struct path_cxt *parent)
+{
+ struct sysfs_blkdev *blk;
+ int rc;
+ char buf[sizeof(_PATH_SYS_DEVBLOCK)
+ + sizeof(stringify_value(UINT32_MAX)) * 2
+ + 3];
+
+ /* define path to devno stuff */
+ snprintf(buf, sizeof(buf), _PATH_SYS_DEVBLOCK "/%d:%d", major(devno), minor(devno));
+ rc = ul_path_set_dir(pc, buf);
+ if (rc)
+ return rc;
+
+ /* make sure path exists */
+ rc = ul_path_get_dirfd(pc);
+ if (rc < 0)
+ return rc;
+
+ /* initialize sysfs blkdev specific stuff */
+ blk = ul_path_get_dialect(pc);
+ if (!blk) {
+ DBG(CXT, ul_debugobj(pc, "alloc new sysfs handler"));
+ blk = calloc(1, sizeof(struct sysfs_blkdev));
+ if (!blk)
+ return -ENOMEM;
+
+ ul_path_set_dialect(pc, blk, sysfs_blkdev_deinit_path);
+ ul_path_set_enoent_redirect(pc, sysfs_blkdev_enoent_redirect);
+ }
+
+ DBG(CXT, ul_debugobj(pc, "init sysfs stuff"));
+
+ blk->devno = devno;
+ sysfs_blkdev_set_parent(pc, parent);
+
+ return 0;
+}
+
+static void sysfs_blkdev_deinit_path(struct path_cxt *pc)
+{
+ struct sysfs_blkdev *blk;
+
+ if (!pc)
+ return;
+
+ DBG(CXT, ul_debugobj(pc, "deinit"));
+
+ blk = ul_path_get_dialect(pc);
+ if (!blk)
+ return;
+
+ ul_unref_path(blk->parent);
+ free(blk);
+
+ ul_path_set_dialect(pc, NULL, NULL);
+}
+
+int sysfs_blkdev_set_parent(struct path_cxt *pc, struct path_cxt *parent)
+{
+ struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
+
+ if (!pc || !blk)
+ return -EINVAL;
+
+ if (blk->parent) {
+ ul_unref_path(blk->parent);
+ blk->parent = NULL;
+ }
+
+ if (parent) {
+ ul_ref_path(parent);
+ blk->parent = parent;
+ } else
+ blk->parent = NULL;
+
+ DBG(CXT, ul_debugobj(pc, "new parent"));
+ return 0;
+}
+
+struct path_cxt *sysfs_blkdev_get_parent(struct path_cxt *pc)
+{
+ struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
+ return blk ? blk->parent : NULL;
+}
+
+/*
+ * Redirects ENOENT errors to the parent, if the path is to the queue/
+ * sysfs directory. For example
+ *
+ * /sys/dev/block/8:1/queue/logical_block_size redirects to
+ * /sys/dev/block/8:0/queue/logical_block_size
+ */
+static int sysfs_blkdev_enoent_redirect(struct path_cxt *pc, const char *path, int *dirfd)
+{
+ struct sysfs_blkdev *blk = ul_path_get_dialect(pc);
+
+ if (blk && blk->parent && strncmp(path, "queue/", 6) == 0) {
+ *dirfd = ul_path_get_dirfd(blk->parent);
+ if (*dirfd >= 0) {
+ DBG(CXT, ul_debugobj(pc, "%s redirected to parent", path));
+ return 0;
+ }
+ }
+ return 1; /* no redirect */
+}
+
+char *sysfs_blkdev_get_name(struct path_cxt *pc, char *buf, size_t bufsiz)
+{
+ char link[PATH_MAX];
+ char *name;
+ ssize_t sz;
+
+ /* read /sys/dev/block/<maj:min> link */
+ sz = ul_path_readlink(pc, link, sizeof(link) - 1, NULL);
+ if (sz < 0)
+ return NULL;
+ link[sz] = '\0';
+
+ name = strrchr(link, '/');
+ if (!name)
+ return NULL;
+
+ name++;
+ sz = strlen(name);
+ if ((size_t) sz + 1 > bufsiz)
+ return NULL;
+
+ memcpy(buf, name, sz + 1);
+ sysfs_devname_sys_to_dev(buf);
+ return buf;
+}
+
+int sysfs_blkdev_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
+{
+ char path[NAME_MAX + 6 + 1];
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (d->d_type != DT_DIR &&
+ d->d_type != DT_LNK &&
+ d->d_type != DT_UNKNOWN)
+ return 0;
+#endif
+ if (parent_name) {
+ const char *p = parent_name;
+ size_t len;
+
+ /* /dev/sda --> "sda" */
+ if (*parent_name == '/') {
+ p = strrchr(parent_name, '/');
+ if (!p)
+ return 0;
+ p++;
+ }
+
+ len = strlen(p);
+ if (strlen(d->d_name) <= len)
+ return 0;
+
+ /* partitions subdir name is
+ * "<parent>[:digit:]" or "<parent>p[:digit:]"
+ */
+ return strncmp(p, d->d_name, len) == 0 &&
+ ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1)))
+ || isdigit(*(d->d_name + len)));
+ }
+
+ /* Cannot use /partition file, not supported on old sysfs */
+ snprintf(path, sizeof(path), "%s/start", d->d_name);
+
+ return faccessat(dirfd(dir), path, R_OK, 0) == 0;
+}
+
+int sysfs_blkdev_count_partitions(struct path_cxt *pc, const char *devname)
+{
+ DIR *dir;
+ struct dirent *d;
+ int r = 0;
+
+ dir = ul_path_opendir(pc, NULL);
+ if (!dir)
+ return 0;
+
+ while ((d = xreaddir(dir))) {
+ if (sysfs_blkdev_is_partition_dirent(dir, d, devname))
+ r++;
+ }
+
+ closedir(dir);
+ return r;
+}
+
+/*
+ * Converts @partno (partition number) to devno of the partition.
+ * The @pc handles wholedisk device.
+ *
+ * Note that this code does not expect any special format of the
+ * partitions devnames.
+ */
+dev_t sysfs_blkdev_partno_to_devno(struct path_cxt *pc, int partno)
+{
+ DIR *dir;
+ struct dirent *d;
+ dev_t devno = 0;
+
+ dir = ul_path_opendir(pc, NULL);
+ if (!dir)
+ return 0;
+
+ while ((d = xreaddir(dir))) {
+ int n;
+
+ if (!sysfs_blkdev_is_partition_dirent(dir, d, NULL))
+ continue;
+
+ if (ul_path_readf_s32(pc, &n, "%s/partition", d->d_name))
+ continue;
+
+ if (n == partno) {
+ if (ul_path_readf_majmin(pc, &devno, "%s/dev", d->d_name) == 0)
+ break;
+ }
+ }
+
+ closedir(dir);
+ DBG(CXT, ul_debugobj(pc, "partno (%d) -> devno (%d)", (int) partno, (int) devno));
+ return devno;
+}
+
+
+/*
+ * Returns slave name if there is only one slave, otherwise returns NULL.
+ * The result should be deallocated by free().
+ */
+char *sysfs_blkdev_get_slave(struct path_cxt *pc)
+{
+ DIR *dir;
+ struct dirent *d;
+ char *name = NULL;
+
+ dir = ul_path_opendir(pc, "slaves");
+ if (!dir)
+ return NULL;
+
+ while ((d = xreaddir(dir))) {
+ if (name)
+ goto err; /* more slaves */
+ name = strdup(d->d_name);
+ }
+
+ closedir(dir);
+ return name;
+err:
+ free(name);
+ closedir(dir);
+ return NULL;
+}
+
+
+#define SUBSYSTEM_LINKNAME "/subsystem"
+
+/*
+ * For example:
+ *
+ * chain: /sys/dev/block/../../devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/ \
+ * 1-1.2:1.0/host65/target65:0:0/65:0:0:0/block/sdb
+ *
+ * The function check if <chain>/subsystem symlink exists, if yes then returns
+ * basename of the readlink result, and remove the last subdirectory from the
+ * <chain> path.
+ */
+static char *get_subsystem(char *chain, char *buf, size_t bufsz)
+{
+ size_t len;
+ char *p;
+
+ if (!chain || !*chain)
+ return NULL;
+
+ len = strlen(chain);
+ if (len + sizeof(SUBSYSTEM_LINKNAME) > PATH_MAX)
+ return NULL;
+
+ do {
+ ssize_t sz;
+
+ /* append "/subsystem" to the path */
+ memcpy(chain + len, SUBSYSTEM_LINKNAME, sizeof(SUBSYSTEM_LINKNAME));
+
+ /* try if subsystem symlink exists */
+ sz = readlink(chain, buf, bufsz - 1);
+
+ /* remove last subsystem from chain */
+ chain[len] = '\0';
+ p = strrchr(chain, '/');
+ if (p) {
+ *p = '\0';
+ len = p - chain;
+ }
+
+ if (sz > 0) {
+ /* we found symlink to subsystem, return basename */
+ buf[sz] = '\0';
+ return basename(buf);
+ }
+
+ } while (p);
+
+ return NULL;
+}
+
+/*
+ * Returns complete path to the device, the patch contains all subsystems
+ * used for the device.
+ */
+char *sysfs_blkdev_get_devchain(struct path_cxt *pc, char *buf, size_t bufsz)
+{
+ /* read /sys/dev/block/<maj>:<min> symlink */
+ ssize_t sz = ul_path_readlink(pc, buf, bufsz, NULL);
+ const char *prefix;
+ size_t psz = 0;
+
+ if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz)
+ return NULL;
+
+ buf[sz++] = '\0';
+ prefix = ul_path_get_prefix(pc);
+ if (prefix)
+ psz = strlen(prefix);
+
+ /* create absolute patch from the link */
+ memmove(buf + psz + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz);
+ if (prefix)
+ memcpy(buf, prefix, psz);
+
+ memcpy(buf + psz, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1);
+ return buf;
+}
+
+/*
+ * The @subsys returns the next subsystem in the chain. Function modifies
+ * @devchain string.
+ *
+ * Returns: 0 in success, <0 on error, 1 on end of chain
+ */
+int sysfs_blkdev_next_subsystem(struct path_cxt *pc __attribute__((unused)),
+ char *devchain, char **subsys)
+{
+ char subbuf[PATH_MAX];
+ char *sub;
+
+ if (!subsys || !devchain)
+ return -EINVAL;
+
+ *subsys = NULL;
+
+ while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) {
+ *subsys = strdup(sub);
+ if (!*subsys)
+ return -ENOMEM;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int is_hotpluggable_subsystem(const char *name)
+{
+ static const char * const hotplug_subsystems[] = {
+ "usb",
+ "ieee1394",
+ "pcmcia",
+ "mmc",
+ "ccw"
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(hotplug_subsystems); i++)
+ if (strcmp(name, hotplug_subsystems[i]) == 0)
+ return 1;
+
+ return 0;
+}
+
+int sysfs_blkdev_is_hotpluggable(struct path_cxt *pc)
+{
+ char buf[PATH_MAX], *chain, *sub;
+ int rc = 0;
+
+
+ /* check /sys/dev/block/<maj>:<min>/removable attribute */
+ if (ul_path_read_s32(pc, &rc, "removable") == 0 && rc == 1)
+ return 1;
+
+ chain = sysfs_blkdev_get_devchain(pc, buf, sizeof(buf));
+
+ while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) {
+ rc = is_hotpluggable_subsystem(sub);
+ if (rc) {
+ free(sub);
+ break;
+ }
+ free(sub);
+ }
+
+ return rc;
+}
+
+static int get_dm_wholedisk(struct path_cxt *pc, char *diskname,
+ size_t len, dev_t *diskdevno)
+{
+ int rc = 0;
+ char *name;
+
+ /* Note, sysfs_blkdev_get_slave() returns the first slave only,
+ * if there is more slaves, then return NULL
+ */
+ name = sysfs_blkdev_get_slave(pc);
+ if (!name)
+ return -1;
+
+ if (diskname && len)
+ xstrncpy(diskname, name, len);
+
+ if (diskdevno) {
+ *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
+ if (!*diskdevno)
+ rc = -1;
+ }
+
+ free(name);
+ return rc;
+}
+
+/*
+ * Returns by @diskdevno whole disk device devno and (optionally) by
+ * @diskname the whole disk device name.
+ */
+int sysfs_blkdev_get_wholedisk( struct path_cxt *pc,
+ char *diskname,
+ size_t len,
+ dev_t *diskdevno)
+{
+ int is_part = 0;
+
+ if (!pc)
+ return -1;
+
+ is_part = ul_path_access(pc, F_OK, "partition") == 0;
+ if (!is_part) {
+ /*
+ * Extra case for partitions mapped by device-mapper.
+ *
+ * All regular partitions (added by BLKPG ioctl or kernel PT
+ * parser) have the /sys/.../partition file. The partitions
+ * mapped by DM don't have such file, but they have "part"
+ * prefix in DM UUID.
+ */
+ char *uuid = NULL, *tmp, *prefix;
+
+ ul_path_read_string(pc, &uuid, "dm/uuid");
+ tmp = uuid;
+ prefix = uuid ? strsep(&tmp, "-") : NULL;
+
+ if (prefix && strncasecmp(prefix, "part", 4) == 0)
+ is_part = 1;
+ free(uuid);
+
+ if (is_part &&
+ get_dm_wholedisk(pc, diskname, len, diskdevno) == 0)
+ /*
+ * partitioned device, mapped by DM
+ */
+ goto done;
+
+ is_part = 0;
+ }
+
+ if (!is_part) {
+ /*
+ * unpartitioned device
+ */
+ if (diskname && !sysfs_blkdev_get_name(pc, diskname, len))
+ goto err;
+ if (diskdevno)
+ *diskdevno = sysfs_blkdev_get_devno(pc);
+
+ } else {
+ /*
+ * partitioned device
+ * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1
+ * - dirname ../../block/sda/sda1 = ../../block/sda
+ * - basename ../../block/sda = sda
+ */
+ char linkpath[PATH_MAX];
+ char *name;
+ ssize_t linklen;
+
+ linklen = ul_path_readlink(pc, linkpath, sizeof(linkpath) - 1, NULL);
+ if (linklen < 0)
+ goto err;
+ linkpath[linklen] = '\0';
+
+ stripoff_last_component(linkpath); /* dirname */
+ name = stripoff_last_component(linkpath); /* basename */
+ if (!name)
+ goto err;
+
+ sysfs_devname_sys_to_dev(name);
+ if (diskname && len)
+ xstrncpy(diskname, name, len);
+
+ if (diskdevno) {
+ *diskdevno = __sysfs_devname_to_devno(ul_path_get_prefix(pc), name, NULL);
+ if (!*diskdevno)
+ goto err;
+ }
+ }
+
+done:
+ return 0;
+err:
+ return -1;
+}
+
+int sysfs_devno_to_wholedisk(dev_t devno, char *diskname,
+ size_t len, dev_t *diskdevno)
+{
+ struct path_cxt *pc;
+ int rc = 0;
+
+ if (!devno)
+ return -EINVAL;
+ pc = ul_new_sysfs_path(devno, NULL, NULL);
+ if (!pc)
+ return -ENOMEM;
+
+ rc = sysfs_blkdev_get_wholedisk(pc, diskname, len, diskdevno);
+ ul_unref_path(pc);
+ return rc;
+}
+
+/*
+ * Returns 1 if the device is private device mapper device. The @uuid
+ * (if not NULL) returns DM device UUID, use free() to deallocate.
+ */
+int sysfs_devno_is_dm_private(dev_t devno, char **uuid)
+{
+ struct path_cxt *pc = NULL;
+ char *id = NULL;
+ int rc = 0;
+
+ pc = ul_new_sysfs_path(devno, NULL, NULL);
+ if (!pc)
+ goto done;
+ if (ul_path_read_string(pc, &id, "dm/uuid") <= 0 || !id)
+ goto done;
+
+ /* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important
+ * is the "LVM" prefix and "-<name>" postfix).
+ */
+ if (strncmp(id, "LVM-", 4) == 0) {
+ char *p = strrchr(id + 4, '-');
+
+ if (p && *(p + 1))
+ rc = 1;
+
+ /* Private Stratis devices prefix the UUID with "stratis-1-private"
+ */
+ } else if (strncmp(id, "stratis-1-private", 17) == 0) {
+ rc = 1;
+ }
+done:
+ ul_unref_path(pc);
+ if (uuid)
+ *uuid = id;
+ else
+ free(id);
+ return rc;
+}
+
+/*
+ * Return 0 or 1, or < 0 in case of error
+ */
+int sysfs_devno_is_wholedisk(dev_t devno)
+{
+ dev_t disk;
+
+ if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0)
+ return -1;
+
+ return devno == disk;
+}
+
+
+int sysfs_blkdev_scsi_get_hctl(struct path_cxt *pc, int *h, int *c, int *t, int *l)
+{
+ char buf[PATH_MAX], *hctl;
+ struct sysfs_blkdev *blk;
+ ssize_t len;
+
+ blk = ul_path_get_dialect(pc);
+
+ if (!blk || blk->hctl_error)
+ return -EINVAL;
+ if (blk->has_hctl)
+ goto done;
+
+ blk->hctl_error = 1;
+ len = ul_path_readlink(pc, buf, sizeof(buf) - 1, "device");
+ if (len < 0)
+ return len;
+
+ buf[len] = '\0';
+ hctl = strrchr(buf, '/');
+ if (!hctl)
+ return -1;
+ hctl++;
+
+ if (sscanf(hctl, "%u:%u:%u:%u", &blk->scsi_host, &blk->scsi_channel,
+ &blk->scsi_target, &blk->scsi_lun) != 4)
+ return -1;
+
+ blk->has_hctl = 1;
+done:
+ if (h)
+ *h = blk->scsi_host;
+ if (c)
+ *c = blk->scsi_channel;
+ if (t)
+ *t = blk->scsi_target;
+ if (l)
+ *l = blk->scsi_lun;
+
+ blk->hctl_error = 0;
+ return 0;
+}
+
+
+static char *scsi_host_attribute_path(
+ struct path_cxt *pc,
+ const char *type,
+ char *buf,
+ size_t bufsz,
+ const char *attr)
+{
+ int len;
+ int host;
+ const char *prefix;
+
+ if (sysfs_blkdev_scsi_get_hctl(pc, &host, NULL, NULL, NULL))
+ return NULL;
+
+ prefix = ul_path_get_prefix(pc);
+ if (!prefix)
+ prefix = "";
+
+ if (attr)
+ len = snprintf(buf, bufsz, "%s%s/%s_host/host%d/%s",
+ prefix, _PATH_SYS_CLASS, type, host, attr);
+ else
+ len = snprintf(buf, bufsz, "%s%s/%s_host/host%d",
+ prefix, _PATH_SYS_CLASS, type, host);
+
+ return (len < 0 || (size_t) len >= bufsz) ? NULL : buf;
+}
+
+char *sysfs_blkdev_scsi_host_strdup_attribute(struct path_cxt *pc,
+ const char *type, const char *attr)
+{
+ char buf[1024];
+ int rc;
+ FILE *f;
+
+ if (!attr || !type ||
+ !scsi_host_attribute_path(pc, type, buf, sizeof(buf), attr))
+ return NULL;
+
+ if (!(f = fopen(buf, "r" UL_CLOEXECSTR)))
+ return NULL;
+
+ rc = fscanf(f, "%1023[^\n]", buf);
+ fclose(f);
+
+ return rc == 1 ? strdup(buf) : NULL;
+}
+
+int sysfs_blkdev_scsi_host_is(struct path_cxt *pc, const char *type)
+{
+ char buf[PATH_MAX];
+ struct stat st;
+
+ if (!type || !scsi_host_attribute_path(pc, type,
+ buf, sizeof(buf), NULL))
+ return 0;
+
+ return stat(buf, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+static char *scsi_attribute_path(struct path_cxt *pc,
+ char *buf, size_t bufsz, const char *attr)
+{
+ int len, h, c, t, l;
+ const char *prefix;
+
+ if (sysfs_blkdev_scsi_get_hctl(pc, &h, &c, &t, &l) != 0)
+ return NULL;
+
+ prefix = ul_path_get_prefix(pc);
+ if (!prefix)
+ prefix = "";
+
+ if (attr)
+ len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d/%s",
+ prefix, _PATH_SYS_SCSI,
+ h,c,t,l, attr);
+ else
+ len = snprintf(buf, bufsz, "%s%s/devices/%d:%d:%d:%d",
+ prefix, _PATH_SYS_SCSI,
+ h,c,t,l);
+ return (len < 0 || (size_t) len >= bufsz) ? NULL : buf;
+}
+
+int sysfs_blkdev_scsi_has_attribute(struct path_cxt *pc, const char *attr)
+{
+ char path[PATH_MAX];
+ struct stat st;
+
+ if (!scsi_attribute_path(pc, path, sizeof(path), attr))
+ return 0;
+
+ return stat(path, &st) == 0;
+}
+
+int sysfs_blkdev_scsi_path_contains(struct path_cxt *pc, const char *pattern)
+{
+ char path[PATH_MAX], linkc[PATH_MAX];
+ struct stat st;
+ ssize_t len;
+
+ if (!scsi_attribute_path(pc, path, sizeof(path), NULL))
+ return 0;
+
+ if (stat(path, &st) != 0)
+ return 0;
+
+ len = readlink(path, linkc, sizeof(linkc) - 1);
+ if (len < 0)
+ return 0;
+
+ linkc[len] = '\0';
+ return strstr(linkc, pattern) != NULL;
+}
+
+static dev_t read_devno(const char *path)
+{
+ FILE *f;
+ int maj = 0, min = 0;
+ dev_t dev = 0;
+
+ f = fopen(path, "r" UL_CLOEXECSTR);
+ if (!f)
+ return 0;
+
+ if (fscanf(f, "%d:%d", &maj, &min) == 2)
+ dev = makedev(maj, min);
+ fclose(f);
+ return dev;
+}
+
+int sysfs_devname_is_hidden(const char *prefix, const char *name)
+{
+ char buf[PATH_MAX];
+ int rc = 0, hidden = 0, len;
+ FILE *f;
+
+ if (strncmp("/dev/", name, 5) == 0)
+ return 0;
+
+ if (!prefix)
+ prefix = "";
+ /*
+ * Create path to /sys/block/<name>/hidden
+ */
+ len = snprintf(buf, sizeof(buf),
+ "%s" _PATH_SYS_BLOCK "/%s/hidden",
+ prefix, name);
+
+ if (len < 0 || (size_t) len + 1 > sizeof(buf))
+ return 0;
+
+ f = fopen(buf, "r" UL_CLOEXECSTR);
+ if (!f)
+ return 0;
+
+ rc = fscanf(f, "%d", &hidden);
+ fclose(f);
+
+ return rc == 1 ? hidden : 0;
+}
+
+
+dev_t __sysfs_devname_to_devno(const char *prefix, const char *name, const char *parent)
+{
+ char buf[PATH_MAX];
+ char *_name = NULL; /* name as encoded in sysfs */
+ dev_t dev = 0;
+ int len;
+
+ if (!prefix)
+ prefix = "";
+
+ assert(name);
+
+ if (strncmp("/dev/", name, 5) == 0) {
+ /*
+ * Read from /dev
+ */
+ struct stat st;
+
+ if (stat(name, &st) == 0) {
+ dev = st.st_rdev;
+ goto done;
+ }
+ name += 5; /* unaccessible, or not node in /dev */
+ }
+
+ _name = strdup(name);
+ if (!_name)
+ goto done;
+ sysfs_devname_dev_to_sys(_name);
+
+ if (parent && strncmp("dm-", name, 3) != 0) {
+ /*
+ * Create path to /sys/block/<parent>/<name>/dev
+ */
+ char *_parent = strdup(parent);
+
+ if (!_parent) {
+ free(_parent);
+ goto done;
+ }
+ sysfs_devname_dev_to_sys(_parent);
+ len = snprintf(buf, sizeof(buf),
+ "%s" _PATH_SYS_BLOCK "/%s/%s/dev",
+ prefix, _parent, _name);
+ free(_parent);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ goto done;
+
+ /* don't try anything else for dm-* */
+ dev = read_devno(buf);
+ goto done;
+ }
+
+ /*
+ * Read from /sys/block/<sysname>/dev
+ */
+ len = snprintf(buf, sizeof(buf),
+ "%s" _PATH_SYS_BLOCK "/%s/dev",
+ prefix, _name);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ goto done;
+ dev = read_devno(buf);
+
+ if (!dev) {
+ /*
+ * Read from /sys/block/<sysname>/device/dev
+ */
+ len = snprintf(buf, sizeof(buf),
+ "%s" _PATH_SYS_BLOCK "/%s/device/dev",
+ prefix, _name);
+ if (len < 0 || (size_t) len >= sizeof(buf))
+ goto done;
+ dev = read_devno(buf);
+ }
+done:
+ free(_name);
+ return dev;
+}
+
+dev_t sysfs_devname_to_devno(const char *name)
+{
+ return __sysfs_devname_to_devno(NULL, name, NULL);
+}
+
+char *sysfs_blkdev_get_path(struct path_cxt *pc, char *buf, size_t bufsiz)
+{
+ const char *name = sysfs_blkdev_get_name(pc, buf, bufsiz);
+ char *res = NULL;
+ size_t sz;
+ struct stat st;
+
+ if (!name)
+ goto done;
+
+ sz = strlen(name);
+ if (sz + sizeof("/dev/") > bufsiz)
+ goto done;
+
+ /* create the final "/dev/<name>" string */
+ memmove(buf + 5, name, sz + 1);
+ memcpy(buf, "/dev/", 5);
+
+ if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == sysfs_blkdev_get_devno(pc))
+ res = buf;
+done:
+ return res;
+}
+
+dev_t sysfs_blkdev_get_devno(struct path_cxt *pc)
+{
+ return ((struct sysfs_blkdev *) ul_path_get_dialect(pc))->devno;
+}
+
+/*
+ * Returns devname (e.g. "/dev/sda1") for the given devno.
+ *
+ * Please, use more robust blkid_devno_to_devname() in your applications.
+ */
+char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz)
+{
+ struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
+ char *res = NULL;
+
+ if (pc) {
+ res = sysfs_blkdev_get_path(pc, buf, bufsiz);
+ ul_unref_path(pc);
+ }
+ return res;
+}
+
+char *sysfs_devno_to_devname(dev_t devno, char *buf, size_t bufsiz)
+{
+ struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
+ char *res = NULL;
+
+ if (pc) {
+ res = sysfs_blkdev_get_name(pc, buf, bufsiz);
+ ul_unref_path(pc);
+ }
+ return res;
+}
+
+int sysfs_devno_count_partitions(dev_t devno)
+{
+ struct path_cxt *pc = ul_new_sysfs_path(devno, NULL, NULL);
+ int n = 0;
+
+ if (pc) {
+ char buf[PATH_MAX + 1];
+ char *name = sysfs_blkdev_get_name(pc, buf, sizeof(buf));
+
+ n = sysfs_blkdev_count_partitions(pc, name);
+ ul_unref_path(pc);
+ }
+ return n;
+}
+
+
+#ifdef TEST_PROGRAM_SYSFS
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ struct path_cxt *pc;
+ char *devname;
+ dev_t devno, disk_devno;
+ char path[PATH_MAX], *sub, *chain;
+ char diskname[32];
+ int i, is_part, rc = EXIT_SUCCESS;
+ uint64_t u64;
+
+ if (argc != 2)
+ errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]);
+
+ ul_sysfs_init_debug();
+
+ devname = argv[1];
+ devno = sysfs_devname_to_devno(devname);
+
+ if (!devno)
+ err(EXIT_FAILURE, "failed to read devno");
+
+ printf("non-context:\n");
+ printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno));
+ printf(" DEVNAME: %s\n", sysfs_devno_to_devname(devno, path, sizeof(path)));
+ printf(" DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path)));
+
+ sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno);
+ printf(" WHOLEDISK-DEVNO: %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno));
+ printf(" WHOLEDISK-DEVNAME: %s\n", diskname);
+
+ pc = ul_new_sysfs_path(devno, NULL, NULL);
+ if (!pc)
+ goto done;
+
+ printf("context based:\n");
+ devno = sysfs_blkdev_get_devno(pc);
+ printf(" DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno));
+ printf(" DEVNAME: %s\n", sysfs_blkdev_get_name(pc, path, sizeof(path)));
+ printf(" DEVPATH: %s\n", sysfs_blkdev_get_path(pc, path, sizeof(path)));
+
+ sysfs_devno_to_wholedisk(devno, diskname, sizeof(diskname), &disk_devno);
+ printf(" WHOLEDISK-DEVNO: %u (%d:%d)\n", (unsigned int) disk_devno, major(disk_devno), minor(disk_devno));
+ printf(" WHOLEDISK-DEVNAME: %s\n", diskname);
+
+ is_part = ul_path_access(pc, F_OK, "partition") == 0;
+ printf(" PARTITION: %s\n", is_part ? "YES" : "NOT");
+
+ if (is_part && disk_devno) {
+ struct path_cxt *disk_pc = ul_new_sysfs_path(disk_devno, NULL, NULL);
+ sysfs_blkdev_set_parent(pc, disk_pc);
+
+ ul_unref_path(disk_pc);
+ }
+
+ printf(" HOTPLUG: %s\n", sysfs_blkdev_is_hotpluggable(pc) ? "yes" : "no");
+ printf(" SLAVES: %d\n", ul_path_count_dirents(pc, "slaves"));
+
+ if (!is_part) {
+ printf("First 5 partitions:\n");
+ for (i = 1; i <= 5; i++) {
+ dev_t dev = sysfs_blkdev_partno_to_devno(pc, i);
+ if (dev)
+ printf("\t#%d %d:%d\n", i, major(dev), minor(dev));
+ }
+ }
+
+ if (ul_path_read_u64(pc, &u64, "size") != 0)
+ printf(" (!) read SIZE failed\n");
+ else
+ printf(" SIZE: %jd\n", u64);
+
+ if (ul_path_read_s32(pc, &i, "queue/hw_sector_size"))
+ printf(" (!) read SECTOR failed\n");
+ else
+ printf(" SECTOR: %d\n", i);
+
+
+ chain = sysfs_blkdev_get_devchain(pc, path, sizeof(path));
+ printf(" SUBSUSTEMS:\n");
+
+ while (chain && sysfs_blkdev_next_subsystem(pc, chain, &sub) == 0) {
+ printf("\t%s\n", sub);
+ free(sub);
+ }
+
+ rc = EXIT_SUCCESS;
+done:
+ ul_unref_path(pc);
+ return rc;
+}
+#endif /* TEST_PROGRAM_SYSFS */
diff --git a/src/utils/lib/timer.c b/src/utils/lib/timer.c
new file mode 100644
index 0000000..c1ea54e
--- /dev/null
+++ b/src/utils/lib/timer.c
@@ -0,0 +1,95 @@
+/*
+ * Please, don't add this file to libcommon because timers requires
+ * -lrt on systems with old libc (and probably also -lpthread for static
+ * build).
+ */
+#include <time.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include "c.h"
+#include "timer.h"
+
+/*
+ * Note the timeout is used for the first signal, then the signal is send
+ * repeatedly in interval ~1% of the original timeout to avoid race in signal
+ * handling -- for example you want to use timer to define timeout for a
+ * syscall:
+ *
+ * setup_timer()
+ * syscall()
+ * cancel_timer()
+ *
+ * if the timeout is too short than it's possible that the signal is delivered
+ * before application enter the syscall function. For this reason timer send
+ * the signal repeatedly.
+ *
+ * The applications need to ensure that they can tolerate multiple signal
+ * deliveries.
+ */
+#ifdef HAVE_TIMER_CREATE
+int setup_timer(struct ul_timer *timer,
+ struct itimerval *timeout,
+ void (*timeout_handler)(int, siginfo_t *, void *))
+{
+ time_t sec = timeout->it_value.tv_sec;
+ long usec = timeout->it_value.tv_usec;
+ struct sigaction sig_a;
+ static struct sigevent sig_e = {
+ .sigev_notify = SIGEV_SIGNAL,
+ .sigev_signo = SIGALRM
+ };
+ struct itimerspec val = {
+ .it_value.tv_sec = sec,
+ .it_value.tv_nsec = usec * 1000,
+ .it_interval.tv_sec = sec / 100,
+ .it_interval.tv_nsec = (sec ? sec % 100 : 1) * 10*1000*1000
+ };
+
+ if (sigemptyset(&sig_a.sa_mask))
+ return 1;
+
+ sig_a.sa_flags = SA_SIGINFO;
+ sig_a.sa_sigaction = timeout_handler;
+
+ if (sigaction(SIGALRM, &sig_a, NULL))
+ return 1;
+ if (timer_create(CLOCK_MONOTONIC, &sig_e, &timer->t_id))
+ return 1;
+ if (timer_settime(timer->t_id, 0, &val, NULL))
+ return 1;
+ return 0;
+}
+void cancel_timer(struct ul_timer *timer)
+{
+ timer_delete(timer->t_id);
+}
+
+#else /* !HAVE_TIMER_CREATE */
+
+int setup_timer(struct ul_timer *timer,
+ struct itimerval *timeout,
+ void (*timeout_handler)(int, siginfo_t *, void *))
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ memset(timer, 0, sizeof(*timer));
+
+ sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
+ sa.sa_sigaction = timeout_handler;
+
+ if (sigaction(SIGALRM, &sa, &timer->old_sa))
+ return 1;
+ if (setitimer(ITIMER_REAL, timeout, &timer->old_timer) != 0)
+ return 1;
+ return 0;
+}
+
+void cancel_timer(struct ul_timer *timer)
+{
+ setitimer(ITIMER_REAL, &timer->old_timer, NULL);
+ sigaction(SIGALRM, &timer->old_sa, NULL);
+
+}
+#endif /* !HAVE_TIMER_CREATE */
diff --git a/src/utils/lib/timeutils.c b/src/utils/lib/timeutils.c
new file mode 100644
index 0000000..8b443cd
--- /dev/null
+++ b/src/utils/lib/timeutils.c
@@ -0,0 +1,611 @@
+/***
+ First set of functions in this file are part of systemd, and were
+ copied to util-linux at August 2013.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with util-linux; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+#include "timeutils.h"
+
+#define WHITESPACE " \t\n\r"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+static int parse_sec(const char *t, usec_t *usec)
+{
+ static const struct {
+ const char *suffix;
+ usec_t usec;
+ } table[] = {
+ { "seconds", USEC_PER_SEC },
+ { "second", USEC_PER_SEC },
+ { "sec", USEC_PER_SEC },
+ { "s", USEC_PER_SEC },
+ { "minutes", USEC_PER_MINUTE },
+ { "minute", USEC_PER_MINUTE },
+ { "min", USEC_PER_MINUTE },
+ { "months", USEC_PER_MONTH },
+ { "month", USEC_PER_MONTH },
+ { "msec", USEC_PER_MSEC },
+ { "ms", USEC_PER_MSEC },
+ { "m", USEC_PER_MINUTE },
+ { "hours", USEC_PER_HOUR },
+ { "hour", USEC_PER_HOUR },
+ { "hr", USEC_PER_HOUR },
+ { "h", USEC_PER_HOUR },
+ { "days", USEC_PER_DAY },
+ { "day", USEC_PER_DAY },
+ { "d", USEC_PER_DAY },
+ { "weeks", USEC_PER_WEEK },
+ { "week", USEC_PER_WEEK },
+ { "w", USEC_PER_WEEK },
+ { "years", USEC_PER_YEAR },
+ { "year", USEC_PER_YEAR },
+ { "y", USEC_PER_YEAR },
+ { "usec", 1ULL },
+ { "us", 1ULL },
+ { "", USEC_PER_SEC }, /* default is sec */
+ };
+
+ const char *p;
+ usec_t r = 0;
+ int something = FALSE;
+
+ assert(t);
+ assert(usec);
+
+ p = t;
+ for (;;) {
+ long long l, z = 0;
+ char *e;
+ unsigned i, n = 0;
+
+ p += strspn(p, WHITESPACE);
+
+ if (*p == 0) {
+ if (!something)
+ return -EINVAL;
+
+ break;
+ }
+
+ errno = 0;
+ l = strtoll(p, &e, 10);
+
+ if (errno > 0)
+ return -errno;
+
+ if (l < 0)
+ return -ERANGE;
+
+ if (*e == '.') {
+ char *b = e + 1;
+
+ errno = 0;
+ z = strtoll(b, &e, 10);
+ if (errno > 0)
+ return -errno;
+
+ if (z < 0)
+ return -ERANGE;
+
+ if (e == b)
+ return -EINVAL;
+
+ n = e - b;
+
+ } else if (e == p)
+ return -EINVAL;
+
+ e += strspn(e, WHITESPACE);
+
+ for (i = 0; i < ARRAY_SIZE(table); i++)
+ if (startswith(e, table[i].suffix)) {
+ usec_t k = (usec_t) z * table[i].usec;
+
+ for (; n > 0; n--)
+ k /= 10;
+
+ r += (usec_t) l *table[i].usec + k;
+ p = e + strlen(table[i].suffix);
+
+ something = TRUE;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(table))
+ return -EINVAL;
+
+ }
+
+ *usec = r;
+
+ return 0;
+}
+
+int parse_timestamp(const char *t, usec_t *usec)
+{
+ static const struct {
+ const char *name;
+ const int nr;
+ } day_nr[] = {
+ { "Sunday", 0 },
+ { "Sun", 0 },
+ { "Monday", 1 },
+ { "Mon", 1 },
+ { "Tuesday", 2 },
+ { "Tue", 2 },
+ { "Wednesday", 3 },
+ { "Wed", 3 },
+ { "Thursday", 4 },
+ { "Thu", 4 },
+ { "Friday", 5 },
+ { "Fri", 5 },
+ { "Saturday", 6 },
+ { "Sat", 6 },
+ };
+
+ const char *k;
+ struct tm tm, copy;
+ time_t x;
+ usec_t plus = 0, minus = 0, ret;
+ int r, weekday = -1;
+ unsigned i;
+
+ /*
+ * Allowed syntaxes:
+ *
+ * 2012-09-22 16:34:22
+ * 2012-09-22T16:34:22
+ * 2012-09-22 16:34 (seconds will be set to 0)
+ * 2012-09-22 (time will be set to 00:00:00)
+ * 16:34:22 (date will be set to today)
+ * 16:34 (date will be set to today, seconds to 0)
+ * now
+ * yesterday (time is set to 00:00:00)
+ * today (time is set to 00:00:00)
+ * tomorrow (time is set to 00:00:00)
+ * +5min
+ * -5days
+ *
+ */
+
+ assert(t);
+ assert(usec);
+
+ x = time(NULL);
+ localtime_r(&x, &tm);
+ tm.tm_isdst = -1;
+
+ if (streq(t, "now"))
+ goto finish;
+
+ else if (streq(t, "today")) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (streq(t, "yesterday")) {
+ tm.tm_mday--;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (streq(t, "tomorrow")) {
+ tm.tm_mday++;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (t[0] == '+') {
+
+ r = parse_sec(t + 1, &plus);
+ if (r < 0)
+ return r;
+
+ goto finish;
+ } else if (t[0] == '-') {
+
+ r = parse_sec(t + 1, &minus);
+ if (r < 0)
+ return r;
+
+ goto finish;
+
+ } else if (endswith(t, " ago")) {
+ char *z;
+
+ z = strndup(t, strlen(t) - 4);
+ if (!z)
+ return -ENOMEM;
+
+ r = parse_sec(z, &minus);
+ free(z);
+ if (r < 0)
+ return r;
+
+ goto finish;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(day_nr); i++) {
+ size_t skip;
+
+ if (!startswith_no_case(t, day_nr[i].name))
+ continue;
+
+ skip = strlen(day_nr[i].name);
+ if (t[skip] != ' ')
+ continue;
+
+ weekday = day_nr[i].nr;
+ t += skip + 1;
+ break;
+ }
+
+ copy = tm;
+ k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%y-%m-%d %H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d %H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%y-%m-%d", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y%m%d%H%M%S", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ return -EINVAL;
+
+ finish:
+ x = mktime(&tm);
+ if (x == (time_t)-1)
+ return -EINVAL;
+
+ if (weekday >= 0 && tm.tm_wday != weekday)
+ return -EINVAL;
+
+ ret = (usec_t) x *USEC_PER_SEC;
+
+ ret += plus;
+ if (ret > minus)
+ ret -= minus;
+ else
+ ret = 0;
+
+ *usec = ret;
+
+ return 0;
+}
+
+/* Returns the difference in seconds between its argument and GMT. If if TP is
+ * invalid or no DST information is available default to UTC, that is, zero.
+ * tzset is called so, for example, 'TZ="UTC" hwclock' will work as expected.
+ * Derived from glibc/time/strftime_l.c
+ */
+int get_gmtoff(const struct tm *tp)
+{
+ if (tp->tm_isdst < 0)
+ return 0;
+
+#if HAVE_TM_GMTOFF
+ return tp->tm_gmtoff;
+#else
+ struct tm tm;
+ struct tm gtm;
+ struct tm ltm = *tp;
+ time_t lt;
+
+ tzset();
+ lt = mktime(&ltm);
+ /* Check if mktime returning -1 is an error or a valid time_t */
+ if (lt == (time_t) -1) {
+ if (! localtime_r(&lt, &tm)
+ || ((ltm.tm_sec ^ tm.tm_sec)
+ | (ltm.tm_min ^ tm.tm_min)
+ | (ltm.tm_hour ^ tm.tm_hour)
+ | (ltm.tm_mday ^ tm.tm_mday)
+ | (ltm.tm_mon ^ tm.tm_mon)
+ | (ltm.tm_year ^ tm.tm_year)))
+ return 0;
+ }
+
+ if (! gmtime_r(&lt, &gtm))
+ return 0;
+
+ /* Calculate the GMT offset, that is, the difference between the
+ * TP argument (ltm) and GMT (gtm).
+ *
+ * Compute intervening leap days correctly even if year is negative.
+ * Take care to avoid int overflow in leap day calculations, but it's OK
+ * to assume that A and B are close to each other.
+ */
+ int a4 = (ltm.tm_year >> 2) + (1900 >> 2) - ! (ltm.tm_year & 3);
+ int b4 = (gtm.tm_year >> 2) + (1900 >> 2) - ! (gtm.tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+
+ int years = ltm.tm_year - gtm.tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (ltm.tm_yday - gtm.tm_yday));
+
+ return (60 * (60 * (24 * days + (ltm.tm_hour - gtm.tm_hour))
+ + (ltm.tm_min - gtm.tm_min)) + (ltm.tm_sec - gtm.tm_sec));
+#endif
+}
+
+static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf, size_t bufsz)
+{
+ char *p = buf;
+ int len;
+
+ if (flags & ISO_DATE) {
+ len = snprintf(p, bufsz, "%4ld-%.2d-%.2d",
+ tm->tm_year + (long) 1900,
+ tm->tm_mon + 1, tm->tm_mday);
+ if (len < 0 || (size_t) len > bufsz)
+ goto err;
+ bufsz -= len;
+ p += len;
+ }
+
+ if ((flags & ISO_DATE) && (flags & ISO_TIME)) {
+ if (bufsz < 1)
+ goto err;
+ *p++ = (flags & ISO_T) ? 'T' : ' ';
+ bufsz--;
+ }
+
+ if (flags & ISO_TIME) {
+ len = snprintf(p, bufsz, "%02d:%02d:%02d", tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+ if (len < 0 || (size_t) len > bufsz)
+ goto err;
+ bufsz -= len;
+ p += len;
+ }
+
+ if (flags & ISO_DOTUSEC) {
+ len = snprintf(p, bufsz, ".%06ld", (long) usec);
+ if (len < 0 || (size_t) len > bufsz)
+ goto err;
+ bufsz -= len;
+ p += len;
+
+ } else if (flags & ISO_COMMAUSEC) {
+ len = snprintf(p, bufsz, ",%06ld", (long) usec);
+ if (len < 0 || (size_t) len > bufsz)
+ goto err;
+ bufsz -= len;
+ p += len;
+ }
+
+ if (flags & ISO_TIMEZONE) {
+ int tmin = get_gmtoff(tm) / 60;
+ int zhour = tmin / 60;
+ int zmin = abs(tmin % 60);
+ len = snprintf(p, bufsz, "%+03d:%02d", zhour,zmin);
+ if (len < 0 || (size_t) len > bufsz)
+ goto err;
+ }
+ return 0;
+ err:
+ warnx(_("format_iso_time: buffer overflow."));
+ return -1;
+}
+
+/* timeval to ISO 8601 */
+int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz)
+{
+ struct tm tm;
+ struct tm *rc;
+
+ if (flags & ISO_GMTIME)
+ rc = gmtime_r(&tv->tv_sec, &tm);
+ else
+ rc = localtime_r(&tv->tv_sec, &tm);
+
+ if (rc)
+ return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz);
+
+ warnx(_("time %ld is out of range."), tv->tv_sec);
+ return -1;
+}
+
+/* struct tm to ISO 8601 */
+int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz)
+{
+ return format_iso_time(tm, 0, flags, buf, bufsz);
+}
+
+/* time_t to ISO 8601 */
+int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz)
+{
+ struct tm tm;
+ struct tm *rc;
+
+ if (flags & ISO_GMTIME)
+ rc = gmtime_r(t, &tm);
+ else
+ rc = localtime_r(t, &tm);
+
+ if (rc)
+ return format_iso_time(&tm, 0, flags, buf, bufsz);
+
+ warnx(_("time %ld is out of range."), (long)t);
+ return -1;
+}
+
+/* relative time functions */
+static inline int time_is_thisyear(struct tm const *const tm,
+ struct tm const *const tmnow)
+{
+ return tm->tm_year == tmnow->tm_year;
+}
+
+static inline int time_is_today(struct tm const *const tm,
+ struct tm const *const tmnow)
+{
+ return (tm->tm_yday == tmnow->tm_yday &&
+ time_is_thisyear(tm, tmnow));
+}
+
+int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, size_t bufsz)
+{
+ struct tm tm, tmnow;
+ int rc = 0;
+
+ if (now->tv_sec == 0)
+ gettimeofday(now, NULL);
+
+ localtime_r(t, &tm);
+ localtime_r(&now->tv_sec, &tmnow);
+
+ if (time_is_today(&tm, &tmnow)) {
+ rc = snprintf(buf, bufsz, "%02d:%02d", tm.tm_hour, tm.tm_min);
+ if (rc < 0 || (size_t) rc > bufsz)
+ return -1;
+ rc = 1;
+
+ } else if (time_is_thisyear(&tm, &tmnow)) {
+ if (flags & UL_SHORTTIME_THISYEAR_HHMM)
+ rc = strftime(buf, bufsz, "%b%d/%H:%M", &tm);
+ else
+ rc = strftime(buf, bufsz, "%b%d", &tm);
+ } else
+ rc = strftime(buf, bufsz, "%Y-%b%d", &tm);
+
+ return rc <= 0 ? -1 : 0;
+}
+
+#ifndef HAVE_TIMEGM
+time_t timegm(struct tm *tm)
+{
+ const char *zone = getenv("TZ");
+ time_t ret;
+
+ setenv("TZ", "", 1);
+ tzset();
+ ret = mktime(tm);
+ if (zone)
+ setenv("TZ", zone, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
+}
+#endif /* HAVE_TIMEGM */
+
+#ifdef TEST_PROGRAM_TIMEUTILS
+
+int main(int argc, char *argv[])
+{
+ struct timeval tv = { 0 };
+ char buf[ISO_BUFSIZ];
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s [<time> [<usec>]] | [--timestamp <str>]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(argv[1], "--timestamp") == 0) {
+ usec_t usec;
+
+ parse_timestamp(argv[2], &usec);
+ tv.tv_sec = (time_t) (usec / 1000000);
+ tv.tv_usec = usec % 1000000;
+ } else {
+ tv.tv_sec = strtos64_or_err(argv[1], "failed to parse <time>");
+ if (argc == 3)
+ tv.tv_usec = strtos64_or_err(argv[2], "failed to parse <usec>");
+ }
+
+ strtimeval_iso(&tv, ISO_DATE, buf, sizeof(buf));
+ printf("Date: '%s'\n", buf);
+
+ strtimeval_iso(&tv, ISO_TIME, buf, sizeof(buf));
+ printf("Time: '%s'\n", buf);
+
+ strtimeval_iso(&tv, ISO_DATE | ISO_TIME | ISO_COMMAUSEC | ISO_T,
+ buf, sizeof(buf));
+ printf("Full: '%s'\n", buf);
+
+ strtimeval_iso(&tv, ISO_TIMESTAMP_DOT, buf, sizeof(buf));
+ printf("Zone: '%s'\n", buf);
+
+ return EXIT_SUCCESS;
+}
+
+#endif /* TEST_PROGRAM_TIMEUTILS */
diff --git a/src/utils/lib/ttyutils.c b/src/utils/lib/ttyutils.c
new file mode 100644
index 0000000..7064565
--- /dev/null
+++ b/src/utils/lib/ttyutils.c
@@ -0,0 +1,152 @@
+/*
+ * No copyright is claimed. This code is in the public domain; do with
+ * it what you wish.
+ *
+ * Written by Karel Zak <kzak@redhat.com>
+ */
+#include <ctype.h>
+#include <unistd.h>
+
+#include "c.h"
+#include "ttyutils.h"
+
+
+static int get_env_int(const char *name)
+{
+ const char *cp = getenv(name);
+
+ if (cp) {
+ char *end = NULL;
+ long x;
+
+ errno = 0;
+ x = strtol(cp, &end, 10);
+
+ if (errno == 0 && end && *end == '\0' && end > cp &&
+ x > 0 && x <= INT_MAX)
+ return x;
+ }
+
+ return -1;
+}
+
+int get_terminal_dimension(int *cols, int *lines)
+{
+ int c = 0, l = 0;
+
+#if defined(TIOCGWINSZ)
+ struct winsize w_win;
+ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &w_win) == 0) {
+ c = w_win.ws_col;
+ l = w_win.ws_row;
+ }
+#elif defined(TIOCGSIZE)
+ struct ttysize t_win;
+ if (ioctl (STDOUT_FILENO, TIOCGSIZE, &t_win) == 0) {
+ c = t_win.ts_cols;
+ l = t_win.ts_lines;
+ }
+#endif
+ if (cols) {
+ if (c <= 0)
+ c = get_env_int("COLUMNS");
+ *cols = c;
+ }
+ if (lines) {
+ if (l <= 0)
+ l = get_env_int("LINES");
+ *lines = l;
+ }
+ return 0;
+}
+
+int get_terminal_width(int default_width)
+{
+ int width = 0;
+
+ get_terminal_dimension(&width, NULL);
+
+ return width > 0 ? width : default_width;
+}
+
+int get_terminal_stdfd(void)
+{
+ if (isatty(STDIN_FILENO))
+ return STDIN_FILENO;
+ if (isatty(STDOUT_FILENO))
+ return STDOUT_FILENO;
+ if (isatty(STDERR_FILENO))
+ return STDERR_FILENO;
+
+ return -EINVAL;
+}
+
+int get_terminal_name(const char **path,
+ const char **name,
+ const char **number)
+{
+ const char *tty;
+ const char *p;
+ int fd;
+
+
+ if (name)
+ *name = NULL;
+ if (path)
+ *path = NULL;
+ if (number)
+ *number = NULL;
+
+ fd = get_terminal_stdfd();
+ if (fd < 0)
+ return fd; /* error */
+
+ tty = ttyname(fd);
+ if (!tty)
+ return -1;
+
+ if (path)
+ *path = tty;
+ if (name || number)
+ tty = strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty;
+ if (name)
+ *name = tty;
+ if (number) {
+ for (p = tty; p && *p; p++) {
+ if (isdigit(*p)) {
+ *number = p;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int get_terminal_type(const char **type)
+{
+ *type = getenv("TERM");
+ if (*type)
+ return -EINVAL;
+ return 0;
+}
+
+#ifdef TEST_PROGRAM_TTYUTILS
+# include <stdlib.h>
+int main(void)
+{
+ const char *path, *name, *num;
+ int c, l;
+
+ if (get_terminal_name(&path, &name, &num) == 0) {
+ fprintf(stderr, "tty path: %s\n", path);
+ fprintf(stderr, "tty name: %s\n", name);
+ fprintf(stderr, "tty number: %s\n", num);
+ }
+ get_terminal_dimension(&c, &l);
+ fprintf(stderr, "tty cols: %d\n", c);
+ fprintf(stderr, "tty lines: %d\n", l);
+
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM_TTYUTILS */
diff --git a/src/utils/libsmartcols/CMakeLists.txt b/src/utils/libsmartcols/CMakeLists.txt
new file mode 100644
index 0000000..c8deb72
--- /dev/null
+++ b/src/utils/libsmartcols/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-utils-libsmartcols)
+
+add_library(libsmartcols STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/buffer.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/calculate.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/cell.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/column.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/fput.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/grouping.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/init.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/iter.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/line.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/print-api.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/print.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/symbols.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/table.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/version.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/walk.c)
+target_include_directories(libsmartcols PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/../lib)
+target_link_libraries(libsmartcols LINK_PUBLIC libcommon)
diff --git a/src/utils/libsmartcols/src/buffer.c b/src/utils/libsmartcols/src/buffer.c
new file mode 100644
index 0000000..d376e8f
--- /dev/null
+++ b/src/utils/libsmartcols/src/buffer.c
@@ -0,0 +1,152 @@
+
+#include "smartcolsP.h"
+#include "mbsalign.h"
+
+/* This is private struct to work with output data */
+struct libscols_buffer {
+ char *begin; /* begin of the buffer */
+ char *cur; /* current end of the buffer */
+ char *encdata; /* encoded buffer mbs_safe_encode() */
+
+ size_t bufsz; /* size of the buffer */
+ size_t art_idx; /* begin of the tree ascii art or zero */
+};
+
+struct libscols_buffer *new_buffer(size_t sz)
+{
+ struct libscols_buffer *buf = malloc(sz + sizeof(struct libscols_buffer));
+
+ if (!buf)
+ return NULL;
+
+ buf->cur = buf->begin = ((char *) buf) + sizeof(struct libscols_buffer);
+ buf->encdata = NULL;
+ buf->bufsz = sz;
+
+ DBG(BUFF, ul_debugobj(buf, "alloc (size=%zu)", sz));
+ return buf;
+}
+
+void free_buffer(struct libscols_buffer *buf)
+{
+ if (!buf)
+ return;
+ DBG(BUFF, ul_debugobj(buf, "dealloc"));
+ free(buf->encdata);
+ free(buf);
+}
+
+int buffer_reset_data(struct libscols_buffer *buf)
+{
+ if (!buf)
+ return -EINVAL;
+
+ /*DBG(BUFF, ul_debugobj(buf, "reset data"));*/
+ buf->begin[0] = '\0';
+ buf->cur = buf->begin;
+ buf->art_idx = 0;
+ return 0;
+}
+
+int buffer_append_data(struct libscols_buffer *buf, const char *str)
+{
+ size_t maxsz, sz;
+
+ if (!buf)
+ return -EINVAL;
+ if (!str || !*str)
+ return 0;
+
+ sz = strlen(str);
+ maxsz = buf->bufsz - (buf->cur - buf->begin);
+
+ if (maxsz <= sz)
+ return -EINVAL;
+ memcpy(buf->cur, str, sz + 1);
+ buf->cur += sz;
+ return 0;
+}
+
+int buffer_append_ntimes(struct libscols_buffer *buf, size_t n, const char *str)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ int rc = buffer_append_data(buf, str);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+int buffer_set_data(struct libscols_buffer *buf, const char *str)
+{
+ int rc = buffer_reset_data(buf);
+ return rc ? rc : buffer_append_data(buf, str);
+}
+
+/* save the current buffer position to art_idx */
+void buffer_set_art_index(struct libscols_buffer *buf)
+{
+ if (buf) {
+ buf->art_idx = buf->cur - buf->begin;
+ /*DBG(BUFF, ul_debugobj(buf, "art index: %zu", buf->art_idx));*/
+ }
+}
+
+char *buffer_get_data(struct libscols_buffer *buf)
+{
+ return buf ? buf->begin : NULL;
+}
+
+size_t buffer_get_size(struct libscols_buffer *buf)
+{
+ return buf ? buf->bufsz : 0;
+}
+
+/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
+char *buffer_get_safe_data(struct libscols_table *tb,
+ struct libscols_buffer *buf,
+ size_t *cells,
+ const char *safechars)
+{
+ char *data = buffer_get_data(buf);
+ char *res = NULL;
+
+ if (!data)
+ goto nothing;
+
+ if (!buf->encdata) {
+ buf->encdata = malloc(mbs_safe_encode_size(buf->bufsz) + 1);
+ if (!buf->encdata)
+ goto nothing;
+ }
+
+ if (scols_table_is_noencoding(tb)) {
+ *cells = mbs_width(data);
+ strcpy(buf->encdata, data);
+ res = buf->encdata;
+ } else {
+ res = mbs_safe_encode_to_buffer(data, cells, buf->encdata, safechars);
+ }
+
+ if (!res || !*cells || *cells == (size_t) -1)
+ goto nothing;
+ return res;
+nothing:
+ *cells = 0;
+ return NULL;
+}
+
+/* returns size in bytes of the ascii art (according to art_idx) in safe encoding */
+size_t buffer_get_safe_art_size(struct libscols_buffer *buf)
+{
+ char *data = buffer_get_data(buf);
+ size_t bytes = 0;
+
+ if (!data || !buf->art_idx)
+ return 0;
+
+ mbs_safe_nwidth(data, buf->art_idx, &bytes);
+ return bytes;
+}
diff --git a/src/utils/libsmartcols/src/calculate.c b/src/utils/libsmartcols/src/calculate.c
new file mode 100644
index 0000000..b6137fd
--- /dev/null
+++ b/src/utils/libsmartcols/src/calculate.c
@@ -0,0 +1,454 @@
+#include "smartcolsP.h"
+#include "mbsalign.h"
+
+static void dbg_column(struct libscols_table *tb, struct libscols_column *cl)
+{
+ if (scols_column_is_hidden(cl)) {
+ DBG(COL, ul_debugobj(cl, "%s (hidden) ignored", cl->header.data));
+ return;
+ }
+
+ DBG(COL, ul_debugobj(cl, "%15s seq=%zu, width=%zd, "
+ "hint=%d, avg=%zu, max=%zu, min=%zu, "
+ "extreme=%s %s",
+
+ cl->header.data, cl->seqnum, cl->width,
+ cl->width_hint > 1 ? (int) cl->width_hint :
+ (int) (cl->width_hint * tb->termwidth),
+ cl->width_avg,
+ cl->width_max,
+ cl->width_min,
+ cl->is_extreme ? "yes" : "not",
+ cl->flags & SCOLS_FL_TRUNC ? "trunc" : ""));
+}
+
+static void dbg_columns(struct libscols_table *tb)
+{
+ struct libscols_iter itr;
+ struct libscols_column *cl;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0)
+ dbg_column(tb, cl);
+}
+
+static int count_cell_width(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf)
+{
+ size_t len;
+ char *data;
+ int rc;
+
+ rc = __cell_to_buffer(tb, ln, cl, buf);
+ if (rc)
+ return rc;
+
+ data = buffer_get_data(buf);
+ if (!data)
+ len = 0;
+ else if (scols_column_is_customwrap(cl))
+ len = cl->wrap_chunksize(cl, data, cl->wrapfunc_data);
+ else if (scols_table_is_noencoding(tb))
+ len = mbs_width(data);
+ else
+ len = mbs_safe_width(data);
+
+ if (len == (size_t) -1) /* ignore broken multibyte strings */
+ len = 0;
+ cl->width_max = max(len, cl->width_max);
+
+ if (cl->is_extreme && cl->width_avg && len > cl->width_avg * 2)
+ return 0;
+
+ if (scols_column_is_noextremes(cl)) {
+ cl->extreme_sum += len;
+ cl->extreme_count++;
+ }
+ cl->width = max(len, cl->width);
+ if (scols_column_is_tree(cl)) {
+ size_t treewidth = buffer_get_safe_art_size(buf);
+ cl->width_treeart = max(cl->width_treeart, treewidth);
+ }
+ return 0;
+}
+
+
+static int walk_count_cell_width(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ void *data)
+{
+ return count_cell_width(tb, ln, cl, (struct libscols_buffer *) data);
+}
+
+/*
+ * This function counts column width.
+ *
+ * For the SCOLS_FL_NOEXTREMES columns it is possible to call this function
+ * two times. The first pass counts the width and average width. If the column
+ * contains fields that are too large (a width greater than 2 * average) then
+ * the column is marked as "extreme". In the second pass all extreme fields
+ * are ignored and the column width is counted from non-extreme fields only.
+ */
+static int count_column_width(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf)
+{
+ int rc = 0, no_header = 0;
+
+ assert(tb);
+ assert(cl);
+
+ cl->width = 0;
+ if (!cl->width_min) {
+ const char *data;
+
+ if (cl->width_hint < 1 && scols_table_is_maxout(tb) && tb->is_term) {
+ cl->width_min = (size_t) (cl->width_hint * tb->termwidth);
+ if (cl->width_min && !is_last_column(cl))
+ cl->width_min--;
+ }
+
+ data = scols_cell_get_data(&cl->header);
+ if (data) {
+ size_t len = scols_table_is_noencoding(tb) ?
+ mbs_width(data) : mbs_safe_width(data);
+ cl->width_min = max(cl->width_min, len);
+ } else
+ no_header = 1;
+
+ if (!cl->width_min)
+ cl->width_min = 1;
+ }
+
+ if (scols_table_is_tree(tb)) {
+ /* Count width for tree */
+ rc = scols_walk_tree(tb, cl, walk_count_cell_width, (void *) buf);
+ if (rc)
+ goto done;
+ } else {
+ /* Count width for list */
+ struct libscols_iter itr;
+ struct libscols_line *ln;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ rc = count_cell_width(tb, ln, cl, buf);
+ if (rc)
+ goto done;
+ }
+ }
+
+ if (scols_column_is_tree(cl) && has_groups(tb)) {
+ /* We don't fill buffer with groups tree ascii art during width
+ * calculation. The print function only enlarge grpset[] and we
+ * calculate final width from grpset_size.
+ */
+ size_t gprwidth = tb->grpset_size + 1;
+ cl->width_treeart += gprwidth;
+ cl->width_max += gprwidth;
+ cl->width += gprwidth;
+ if (cl->extreme_count)
+ cl->extreme_sum += gprwidth;
+ }
+
+ if (cl->extreme_count && cl->width_avg == 0) {
+ cl->width_avg = cl->extreme_sum / cl->extreme_count;
+ if (cl->width_avg && cl->width_max > cl->width_avg * 2)
+ cl->is_extreme = 1;
+ }
+
+ /* enlarge to minimal width */
+ if (cl->width < cl->width_min && !scols_column_is_strict_width(cl))
+ cl->width = cl->width_min;
+
+ /* use absolute size for large columns */
+ else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint
+ && cl->width_min < (size_t) cl->width_hint)
+
+ cl->width = (size_t) cl->width_hint;
+
+
+ /* Column without header and data, set minimal size to zero (default is 1) */
+ if (cl->width_max == 0 && no_header && cl->width_min == 1 && cl->width <= 1)
+ cl->width = cl->width_min = 0;
+
+done:
+ ON_DBG(COL, dbg_column(tb, cl));
+ return rc;
+}
+
+/*
+ * This is core of the scols_* voodoo...
+ */
+int __scols_calculate(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+ size_t width = 0, width_min = 0; /* output width */
+ int stage, rc = 0;
+ int extremes = 0, group_ncolumns = 0;
+ size_t colsepsz;
+
+
+ DBG(TAB, ul_debugobj(tb, "-----calculate-(termwidth=%zu)-----", tb->termwidth));
+ tb->is_dummy_print = 1;
+
+ colsepsz = scols_table_is_noencoding(tb) ?
+ mbs_width(colsep(tb)) :
+ mbs_safe_width(colsep(tb));
+
+ if (has_groups(tb))
+ group_ncolumns = 1;
+
+ /* set basic columns width
+ */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ int is_last;
+
+ if (scols_column_is_hidden(cl))
+ continue;
+
+ /* we print groups chart only for the for the first tree column */
+ if (scols_column_is_tree(cl) && group_ncolumns == 1) {
+ cl->is_groups = 1;
+ group_ncolumns++;
+ }
+
+ rc = count_column_width(tb, cl, buf);
+ if (rc)
+ goto done;
+
+ is_last = is_last_column(cl);
+
+ width += cl->width + (is_last ? 0 : colsepsz); /* separator for non-last column */
+ width_min += cl->width_min + (is_last ? 0 : colsepsz);
+ if (cl->is_extreme)
+ extremes++;
+ }
+
+ if (!tb->is_term) {
+ DBG(TAB, ul_debugobj(tb, " non-terminal output"));
+ goto done;
+ }
+
+ /* be paranoid */
+ if (width_min > tb->termwidth && scols_table_is_maxout(tb)) {
+ DBG(TAB, ul_debugobj(tb, " min width larger than terminal! [width=%zu, term=%zu]", width_min, tb->termwidth));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (width_min > tb->termwidth
+ && scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ width_min--;
+ cl->width_min--;
+ }
+ DBG(TAB, ul_debugobj(tb, " min width reduced to %zu", width_min));
+ }
+
+ /* reduce columns with extreme fields */
+ if (width > tb->termwidth && extremes) {
+ DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)"));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ size_t org_width;
+
+ if (!cl->is_extreme || scols_column_is_hidden(cl))
+ continue;
+
+ org_width = cl->width;
+ rc = count_column_width(tb, cl, buf);
+ if (rc)
+ goto done;
+
+ if (org_width > cl->width)
+ width -= org_width - cl->width;
+ else
+ extremes--; /* hmm... nothing reduced */
+ }
+ }
+
+ if (width < tb->termwidth) {
+ if (extremes) {
+ DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)"));
+
+ /* enlarge the first extreme column */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ size_t add;
+
+ if (!cl->is_extreme || scols_column_is_hidden(cl))
+ continue;
+
+ /* this column is too large, ignore?
+ if (cl->width_max - cl->width >
+ (tb->termwidth - width))
+ continue;
+ */
+
+ add = tb->termwidth - width;
+ if (add && cl->width + add > cl->width_max)
+ add = cl->width_max - cl->width;
+
+ cl->width += add;
+ width += add;
+
+ if (width == tb->termwidth)
+ break;
+ }
+ }
+
+ if (width < tb->termwidth && scols_table_is_maxout(tb)) {
+ DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)"));
+
+ /* try enlarging all columns */
+ while (width < tb->termwidth) {
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ cl->width++;
+ width++;
+ if (width == tb->termwidth)
+ break;
+ }
+ }
+ } else if (width < tb->termwidth) {
+ /* enlarge the last column */
+ struct libscols_column *col = list_entry(
+ tb->tb_columns.prev, struct libscols_column, cl_columns);
+
+ DBG(TAB, ul_debugobj(tb, " enlarge width (last column)"));
+
+ if (!scols_column_is_right(col) && tb->termwidth - width > 0) {
+ col->width += tb->termwidth - width;
+ width = tb->termwidth;
+ }
+ }
+ }
+
+ /* bad, we have to reduce output width, this is done in three stages:
+ *
+ * 1) trunc relative with trunc flag if the column width is greater than
+ * expected column width (it means "width_hint * terminal_width").
+ *
+ * 2) trunc all with trunc flag
+ *
+ * 3) trunc relative without trunc flag
+ *
+ * Note that SCOLS_FL_WRAP (if no custom wrap function is specified) is
+ * interpreted as SCOLS_FL_TRUNC.
+ */
+ for (stage = 1; width > tb->termwidth && stage <= 3; ) {
+ size_t org_width = width;
+
+ DBG(TAB, ul_debugobj(tb, " reduce width - #%d stage (current=%zu, wanted=%zu)",
+ stage, width, tb->termwidth));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+
+ int trunc_flag = 0;
+
+ DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)",
+ cl->header.data, cl->width, cl->width_treeart));
+ if (scols_column_is_hidden(cl))
+ continue;
+ if (width <= tb->termwidth)
+ break;
+
+ /* never truncate if already minimal width */
+ if (cl->width == cl->width_min)
+ continue;
+
+ /* never truncate the tree */
+ if (scols_column_is_tree(cl) && width <= cl->width_treeart)
+ continue;
+
+ /* nothing to truncate */
+ if (cl->width == 0)
+ continue;
+
+ trunc_flag = scols_column_is_trunc(cl)
+ || (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl));
+
+ switch (stage) {
+ /* #1 stage - trunc relative with TRUNC flag */
+ case 1:
+ if (!trunc_flag) /* ignore: missing flag */
+ break;
+ if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */
+ break;
+ if (cl->width < (size_t) (cl->width_hint * tb->termwidth)) /* ignore: smaller than expected width */
+ break;
+
+ DBG(TAB, ul_debugobj(tb, " reducing (relative with flag)"));
+ cl->width--;
+ width--;
+ break;
+
+ /* #2 stage - trunc all with TRUNC flag */
+ case 2:
+ if (!trunc_flag) /* ignore: missing flag */
+ break;
+
+ DBG(TAB, ul_debugobj(tb, " reducing (all with flag)"));
+ cl->width--;
+ width--;
+ break;
+
+ /* #3 stage - trunc relative without flag */
+ case 3:
+ if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */
+ break;
+
+ DBG(TAB, ul_debugobj(tb, " reducing (relative without flag)"));
+ cl->width--;
+ width--;
+ break;
+ }
+
+ /* hide zero width columns */
+ if (cl->width == 0)
+ cl->flags |= SCOLS_FL_HIDDEN;
+ }
+
+ /* the current stage is without effect, go to the next */
+ if (org_width == width)
+ stage++;
+ }
+
+ /* ignore last column(s) or force last column to be truncated if
+ * nowrap mode enabled */
+ if (tb->no_wrap && width > tb->termwidth) {
+ scols_reset_iter(&itr, SCOLS_ITER_BACKWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+
+ if (scols_column_is_hidden(cl))
+ continue;
+ if (width <= tb->termwidth)
+ break;
+ if (width - cl->width < tb->termwidth) {
+ size_t r = width - tb->termwidth;
+
+ cl->flags |= SCOLS_FL_TRUNC;
+ cl->width -= r;
+ width -= r;
+ } else {
+ cl->flags |= SCOLS_FL_HIDDEN;
+ width -= cl->width + colsepsz;
+ }
+ }
+ }
+done:
+ tb->is_dummy_print = 0;
+ DBG(TAB, ul_debugobj(tb, "-----final width: %zu (rc=%d)-----", width, rc));
+ ON_DBG(TAB, dbg_columns(tb));
+
+ return rc;
+}
diff --git a/src/utils/libsmartcols/src/cell.c b/src/utils/libsmartcols/src/cell.c
new file mode 100644
index 0000000..4cd6e59
--- /dev/null
+++ b/src/utils/libsmartcols/src/cell.c
@@ -0,0 +1,257 @@
+/*
+ * cell.c - functions for table handling at the cell level
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: cell
+ * @title: Cell
+ * @short_description: container for your data
+ *
+ * An API to access and modify per-cell data and information. Note that cell is
+ * always part of the line. If you destroy (un-reference) a line than it
+ * destroys all line cells too.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+/*
+ * The cell has no ref-counting, free() and new() functions. All is
+ * handled by libscols_line.
+ */
+
+/**
+ * scols_reset_cell:
+ * @ce: pointer to a struct libscols_cell instance
+ *
+ * Frees the cell's internal data and resets its status.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_reset_cell(struct libscols_cell *ce)
+{
+ if (!ce)
+ return -EINVAL;
+
+ /*DBG(CELL, ul_debugobj(ce, "reset"));*/
+ free(ce->data);
+ free(ce->color);
+ memset(ce, 0, sizeof(*ce));
+ return 0;
+}
+
+/**
+ * scols_cell_set_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @data: data (used for scols_print_table())
+ *
+ * Stores a copy of the @str in @ce, the old data are deallocated by free().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_data(struct libscols_cell *ce, const char *data)
+{
+ return strdup_to_struct_member(ce, data, data);
+}
+
+/**
+ * scols_cell_refer_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @data: data (used for scols_print_table())
+ *
+ * Adds a reference to @str to @ce. The pointer is deallocated by
+ * scols_reset_cell() or scols_unref_line(). This function is mostly designed
+ * for situations when the data for the cell are already composed in allocated
+ * memory (e.g. asprintf()) to avoid extra unnecessary strdup().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_refer_data(struct libscols_cell *ce, char *data)
+{
+ if (!ce)
+ return -EINVAL;
+ free(ce->data);
+ ce->data = data;
+ return 0;
+}
+
+/**
+ * scols_cell_get_data:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: data in @ce or NULL.
+ */
+const char *scols_cell_get_data(const struct libscols_cell *ce)
+{
+ return ce ? ce->data : NULL;
+}
+
+/**
+ * scols_cell_set_userdata:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @data: private user data
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_userdata(struct libscols_cell *ce, void *data)
+{
+ if (!ce)
+ return -EINVAL;
+ ce->userdata = data;
+ return 0;
+}
+
+/**
+ * scols_cell_get_userdata
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: user data
+ */
+void *scols_cell_get_userdata(struct libscols_cell *ce)
+{
+ return ce->userdata;
+}
+
+/**
+ * scols_cmpstr_cells:
+ * @a: pointer to cell
+ * @b: pointer to cell
+ * @data: unused pointer to private data (defined by API)
+ *
+ * Compares cells data by strcmp(). The function is designed for
+ * scols_column_set_cmpfunc() and scols_sort_table().
+ *
+ * Returns: follows strcmp() return values.
+ */
+int scols_cmpstr_cells(struct libscols_cell *a,
+ struct libscols_cell *b,
+ __attribute__((__unused__)) void *data)
+{
+ const char *adata, *bdata;
+
+ if (a == b)
+ return 0;
+
+ adata = scols_cell_get_data(a);
+ bdata = scols_cell_get_data(b);
+
+ if (adata == NULL && bdata == NULL)
+ return 0;
+ if (adata == NULL)
+ return -1;
+ if (bdata == NULL)
+ return 1;
+ return strcmp(adata, bdata);
+}
+
+/**
+ * scols_cell_set_color:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @color: color name or ESC sequence
+ *
+ * Set the color of @ce to @color.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_color(struct libscols_cell *ce, const char *color)
+{
+ if (color && isalpha(*color)) {
+ color = color_sequence_from_colorname(color);
+ if (!color)
+ return -EINVAL;
+ }
+ return strdup_to_struct_member(ce, color, color);
+}
+
+/**
+ * scols_cell_get_color:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: the current color of @ce.
+ */
+const char *scols_cell_get_color(const struct libscols_cell *ce)
+{
+ return ce->color;
+}
+
+/**
+ * scols_cell_set_flags:
+ * @ce: a pointer to a struct libscols_cell instance
+ * @flags: SCOLS_CELL_FL_* flags
+ *
+ * Note that cells in the table are always aligned by column flags. The cell
+ * flags are used for table title only (now).
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_set_flags(struct libscols_cell *ce, int flags)
+{
+ if (!ce)
+ return -EINVAL;
+ ce->flags = flags;
+ return 0;
+}
+
+/**
+ * scols_cell_get_flags:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Returns: the current flags
+ */
+int scols_cell_get_flags(const struct libscols_cell *ce)
+{
+ return ce->flags;
+}
+
+/**
+ * scols_cell_get_alignment:
+ * @ce: a pointer to a struct libscols_cell instance
+ *
+ * Since: 2.30
+ *
+ * Returns: SCOLS_CELL_FL_{RIGHT,CELNTER,LEFT}
+ */
+int scols_cell_get_alignment(const struct libscols_cell *ce)
+{
+ if (ce->flags & SCOLS_CELL_FL_RIGHT)
+ return SCOLS_CELL_FL_RIGHT;
+ if (ce->flags & SCOLS_CELL_FL_CENTER)
+ return SCOLS_CELL_FL_CENTER;
+
+ return SCOLS_CELL_FL_LEFT; /* default */
+}
+
+/**
+ * scols_cell_copy_content:
+ * @dest: a pointer to a struct libscols_cell instance
+ * @src: a pointer to an immutable struct libscols_cell instance
+ *
+ * Copy the contents of @src into @dest.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_cell_copy_content(struct libscols_cell *dest,
+ const struct libscols_cell *src)
+{
+ int rc;
+
+ rc = scols_cell_set_data(dest, scols_cell_get_data(src));
+ if (!rc)
+ rc = scols_cell_set_color(dest, scols_cell_get_color(src));
+ if (!rc)
+ dest->userdata = src->userdata;
+
+ DBG(CELL, ul_debugobj(src, "copy"));
+ return rc;
+}
diff --git a/src/utils/libsmartcols/src/column.c b/src/utils/libsmartcols/src/column.c
new file mode 100644
index 0000000..c11df69
--- /dev/null
+++ b/src/utils/libsmartcols/src/column.c
@@ -0,0 +1,564 @@
+/*
+ * column.c - functions for table handling at the column level
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: column
+ * @title: Column
+ * @short_description: defines output columns formats, headers, etc.
+ *
+ * An API to access and modify per-column data and information.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "mbsalign.h"
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_column:
+ *
+ * Allocates space for a new column.
+ *
+ * Returns: a pointer to a new struct libscols_column instance, NULL in case of an ENOMEM error.
+ */
+struct libscols_column *scols_new_column(void)
+{
+ struct libscols_column *cl;
+
+ cl = calloc(1, sizeof(*cl));
+ if (!cl)
+ return NULL;
+ DBG(COL, ul_debugobj(cl, "alloc"));
+ cl->refcount = 1;
+ INIT_LIST_HEAD(&cl->cl_columns);
+ return cl;
+}
+
+/**
+ * scols_ref_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Increases the refcount of @cl.
+ */
+void scols_ref_column(struct libscols_column *cl)
+{
+ if (cl)
+ cl->refcount++;
+}
+
+/**
+ * scols_unref_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Decreases the refcount of @cl. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_column(struct libscols_column *cl)
+{
+ if (cl && --cl->refcount <= 0) {
+ DBG(COL, ul_debugobj(cl, "dealloc"));
+ list_del(&cl->cl_columns);
+ scols_reset_cell(&cl->header);
+ free(cl->color);
+ free(cl->safechars);
+ free(cl->pending_data_buf);
+ free(cl);
+ }
+}
+
+/**
+ * scols_copy_column:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Creates a new column and copies @cl's data over to it.
+ *
+ * Returns: a pointer to a new struct libscols_column instance.
+ */
+struct libscols_column *scols_copy_column(const struct libscols_column *cl)
+{
+ struct libscols_column *ret;
+
+ if (!cl)
+ return NULL;
+ ret = scols_new_column();
+ if (!ret)
+ return NULL;
+
+ DBG(COL, ul_debugobj(cl, "copy"));
+
+ if (scols_column_set_color(ret, cl->color))
+ goto err;
+ if (scols_cell_copy_content(&ret->header, &cl->header))
+ goto err;
+
+ ret->width = cl->width;
+ ret->width_min = cl->width_min;
+ ret->width_max = cl->width_max;
+ ret->width_avg = cl->width_avg;
+ ret->width_hint = cl->width_hint;
+ ret->flags = cl->flags;
+ ret->is_extreme = cl->is_extreme;
+ ret->is_groups = cl->is_groups;
+
+ return ret;
+err:
+ scols_unref_column(ret);
+ return NULL;
+}
+
+/**
+ * scols_column_set_whint:
+ * @cl: a pointer to a struct libscols_column instance
+ * @whint: a width hint
+ *
+ * Sets the width hint of column @cl to @whint. See scols_table_new_column().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_whint(struct libscols_column *cl, double whint)
+{
+ if (!cl)
+ return -EINVAL;
+
+ cl->width_hint = whint;
+ return 0;
+}
+
+/**
+ * scols_column_get_whint:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The width hint of column @cl, a negative value in case of an error.
+ */
+double scols_column_get_whint(const struct libscols_column *cl)
+{
+ return cl->width_hint;
+}
+
+/**
+ * scols_column_set_flags:
+ * @cl: a pointer to a struct libscols_column instance
+ * @flags: a flag mask
+ *
+ * Sets the flags of @cl to @flags.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_flags(struct libscols_column *cl, int flags)
+{
+ if (!cl)
+ return -EINVAL;
+
+ if (cl->table) {
+ if (!(cl->flags & SCOLS_FL_TREE) && (flags & SCOLS_FL_TREE))
+ cl->table->ntreecols++;
+ else if ((cl->flags & SCOLS_FL_TREE) && !(flags & SCOLS_FL_TREE))
+ cl->table->ntreecols--;
+ }
+
+ DBG(COL, ul_debugobj(cl, "setting flags from 0%x to 0%x", cl->flags, flags));
+ cl->flags = flags;
+ return 0;
+}
+
+/**
+ * scols_column_set_json_type:
+ * @cl: a pointer to a struct libscols_column instance
+ * @type: SCOLS_JSON_* type
+ *
+ * Sets the type used for JSON formatting, the default is SCOLS_JSON_STRING.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.33
+ */
+int scols_column_set_json_type(struct libscols_column *cl, int type)
+{
+ if (!cl)
+ return -EINVAL;
+
+ cl->json_type = type;
+ return 0;
+
+}
+
+/**
+ * scols_column_get_json_type:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Note that SCOLS_JSON_BOOLEAN interprets NULL, empty strings, '0', 'N' and
+ * 'n' as "false"; and everything else as "true".
+ *
+ * Returns: JSON type used for formatting or a negative value in case of an error.
+ *
+ * Since: 2.33
+ */
+int scols_column_get_json_type(const struct libscols_column *cl)
+{
+ return cl ? cl->json_type : -EINVAL;
+}
+
+
+/**
+ * scols_column_get_table:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: pointer to the table where columns is used
+ */
+struct libscols_table *scols_column_get_table(const struct libscols_column *cl)
+{
+ return cl->table;
+}
+
+/**
+ * scols_column_get_flags:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The flag mask of @cl, a negative value in case of an error.
+ */
+int scols_column_get_flags(const struct libscols_column *cl)
+{
+ return cl->flags;
+}
+
+/**
+ * scols_column_get_header:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: A pointer to a struct libscols_cell instance, representing the
+ * header info of column @cl or NULL in case of an error.
+ */
+struct libscols_cell *scols_column_get_header(struct libscols_column *cl)
+{
+ return &cl->header;
+}
+
+/**
+ * scols_column_set_color:
+ * @cl: a pointer to a struct libscols_column instance
+ * @color: color name or ESC sequence
+ *
+ * The default color for data cells and column header.
+ *
+ * If you want to set header specific color then use scols_column_get_header()
+ * and scols_cell_set_color().
+ *
+ * If you want to set data cell specific color the use scols_line_get_cell() +
+ * scols_cell_set_color().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_color(struct libscols_column *cl, const char *color)
+{
+ if (color && isalpha(*color)) {
+ color = color_sequence_from_colorname(color);
+ if (!color)
+ return -EINVAL;
+ }
+ return strdup_to_struct_member(cl, color, color);
+}
+
+/**
+ * scols_column_get_color:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: The current color setting of the column @cl.
+ */
+const char *scols_column_get_color(const struct libscols_column *cl)
+{
+ return cl->color;
+}
+
+/**
+ * scols_wrapnl_nextchunk:
+ * @cl: a pointer to a struct libscols_column instance
+ * @data: string
+ * @userdata: callback private data
+ *
+ * This is built-in function for scols_column_set_wrapfunc(). This function
+ * terminates the current chunk by \0 and returns pointer to the begin of
+ * the next chunk. The chunks are based on \n.
+ *
+ * For example for data "AAA\nBBB\nCCC" the next chunk is "BBB".
+ *
+ * Returns: next chunk
+ *
+ * Since: 2.29
+ */
+char *scols_wrapnl_nextchunk(const struct libscols_column *cl __attribute__((unused)),
+ char *data,
+ void *userdata __attribute__((unused)))
+{
+ char *p = data ? strchr(data, '\n') : NULL;
+
+ if (p) {
+ *p = '\0';
+ return p + 1;
+ }
+ return NULL;
+}
+
+/**
+ * scols_wrapnl_chunksize:
+ * @cl: a pointer to a struct libscols_column instance
+ * @data: string
+ * @userdata: callback private data
+ *
+ * Analyzes @data and returns size of the largest chunk. The chunks are based
+ * on \n. For example for data "AAA\nBBB\nCCCC" the largest chunk size is 4.
+ *
+ * Note that the size has to be based on number of terminal cells rather than
+ * bytes to support multu-byte output.
+ *
+ * Returns: size of the largest chunk.
+ *
+ * Since: 2.29
+ */
+size_t scols_wrapnl_chunksize(const struct libscols_column *cl __attribute__((unused)),
+ const char *data,
+ void *userdata __attribute__((unused)))
+{
+ size_t sum = 0;
+
+ while (data && *data) {
+ const char *p;
+ size_t sz;
+
+ p = strchr(data, '\n');
+ if (p) {
+ sz = cl->table && scols_table_is_noencoding(cl->table) ?
+ mbs_nwidth(data, p - data) :
+ mbs_safe_nwidth(data, p - data, NULL);
+ p++;
+ } else {
+ sz = cl->table && scols_table_is_noencoding(cl->table) ?
+ mbs_width(data) :
+ mbs_safe_width(data);
+ }
+ sum = max(sum, sz);
+ data = p;
+ }
+
+ return sum;
+}
+
+/**
+ * scols_column_set_cmpfunc:
+ * @cl: column
+ * @cmp: pointer to compare function
+ * @data: private data for cmp function
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_column_set_cmpfunc(struct libscols_column *cl,
+ int (*cmp)(struct libscols_cell *,
+ struct libscols_cell *,
+ void *),
+ void *data)
+{
+ if (!cl)
+ return -EINVAL;
+
+ cl->cmpfunc = cmp;
+ cl->cmpfunc_data = data;
+ return 0;
+}
+
+/**
+ * scols_column_set_wrapfunc:
+ * @cl: a pointer to a struct libscols_column instance
+ * @wrap_chunksize: function to return size of the largest chink of data
+ * @wrap_nextchunk: function to return next zero terminated data
+ * @userdata: optional stuff for callbacks
+ *
+ * Extends SCOLS_FL_WRAP and can be used to set custom wrap function. The default
+ * is to wrap by column size, but you can create functions to wrap for example
+ * after \n or after words, etc.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_column_set_wrapfunc(struct libscols_column *cl,
+ size_t (*wrap_chunksize)(const struct libscols_column *,
+ const char *,
+ void *),
+ char * (*wrap_nextchunk)(const struct libscols_column *,
+ char *,
+ void *),
+ void *userdata)
+{
+ if (!cl)
+ return -EINVAL;
+
+ cl->wrap_nextchunk = wrap_nextchunk;
+ cl->wrap_chunksize = wrap_chunksize;
+ cl->wrapfunc_data = userdata;
+ return 0;
+}
+
+/**
+ * scols_column_set_safechars:
+ * @cl: a pointer to a struct libscols_column instance
+ * @safe: safe characters (e.g. "\n\t")
+ *
+ * Use for bytes you don't want to encode on output. This is for example
+ * necessary if you want to use custom wrap function based on \n, in this case
+ * you have to set "\n" as a safe char.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_column_set_safechars(struct libscols_column *cl, const char *safe)
+{
+ return strdup_to_struct_member(cl, safechars, safe);
+}
+
+/**
+ * scols_column_get_safechars:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: safe chars
+ *
+ * Since: 2.29
+ */
+const char *scols_column_get_safechars(const struct libscols_column *cl)
+{
+ return cl->safechars;
+}
+
+/**
+ * scols_column_get_width:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Important note: the column width is unknown until library starts printing
+ * (width is calculated before printing). The function is usable for example in
+ * nextchunk() callback specified by scols_column_set_wrapfunc().
+ *
+ * See also scols_column_get_whint(), it returns wanted size (!= final size).
+ *
+ * Returns: column width
+ *
+ * Since: 2.29
+ */
+size_t scols_column_get_width(const struct libscols_column *cl)
+{
+ return cl->width;
+}
+
+/**
+ * scols_column_is_hidden:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag hidden.
+ *
+ * Returns: 0 or 1
+ *
+ * Since: 2.27
+ */
+int scols_column_is_hidden(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_HIDDEN ? 1 : 0;
+}
+
+/**
+ * scols_column_is_trunc:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag trunc.
+ *
+ * Returns: 0 or 1
+ */
+int scols_column_is_trunc(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_TRUNC ? 1 : 0;
+}
+/**
+ * scols_column_is_tree:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag tree.
+ *
+ * Returns: 0 or 1
+ */
+int scols_column_is_tree(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_TREE ? 1 : 0;
+}
+/**
+ * scols_column_is_right:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag right.
+ *
+ * Returns: 0 or 1
+ */
+int scols_column_is_right(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_RIGHT ? 1 : 0;
+}
+/**
+ * scols_column_is_strict_width:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag strict_width.
+ *
+ * Returns: 0 or 1
+ */
+int scols_column_is_strict_width(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_STRICTWIDTH ? 1 : 0;
+}
+/**
+ * scols_column_is_noextremes:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag no_extremes.
+ *
+ * Returns: 0 or 1
+ */
+int scols_column_is_noextremes(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_NOEXTREMES ? 1 : 0;
+}
+/**
+ * scols_column_is_wrap:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Gets the value of @cl's flag wrap.
+ *
+ * Returns: 0 or 1
+ *
+ * Since: 2.28
+ */
+int scols_column_is_wrap(const struct libscols_column *cl)
+{
+ return cl->flags & SCOLS_FL_WRAP ? 1 : 0;
+}
+/**
+ * scols_column_is_customwrap:
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Returns: 0 or 1
+ *
+ * Since: 2.29
+ */
+int scols_column_is_customwrap(const struct libscols_column *cl)
+{
+ return (cl->flags & SCOLS_FL_WRAP)
+ && cl->wrap_chunksize
+ && cl->wrap_nextchunk ? 1 : 0;
+}
diff --git a/src/utils/libsmartcols/src/fput.c b/src/utils/libsmartcols/src/fput.c
new file mode 100644
index 0000000..b00c3d8
--- /dev/null
+++ b/src/utils/libsmartcols/src/fput.c
@@ -0,0 +1,97 @@
+#include "carefulputc.h"
+#include "smartcolsP.h"
+
+void fput_indent(struct libscols_table *tb)
+{
+ int i;
+
+ for (i = 0; i <= tb->indent; i++)
+ fputs(" ", tb->out);
+}
+
+void fput_table_open(struct libscols_table *tb)
+{
+ tb->indent = 0;
+
+ if (scols_table_is_json(tb)) {
+ fputc('{', tb->out);
+ fputs(linesep(tb), tb->out);
+
+ fput_indent(tb);
+ fputs_quoted(tb->name, tb->out);
+ fputs(": [", tb->out);
+ fputs(linesep(tb), tb->out);
+
+ tb->indent++;
+ tb->indent_last_sep = 1;
+ }
+}
+
+void fput_table_close(struct libscols_table *tb)
+{
+ tb->indent--;
+
+ if (scols_table_is_json(tb)) {
+ fput_indent(tb);
+ fputc(']', tb->out);
+ tb->indent--;
+ fputs(linesep(tb), tb->out);
+ fputc('}', tb->out);
+ tb->indent_last_sep = 1;
+ }
+}
+
+void fput_children_open(struct libscols_table *tb)
+{
+ if (scols_table_is_json(tb)) {
+ fputc(',', tb->out);
+ fputs(linesep(tb), tb->out);
+ fput_indent(tb);
+ fputs("\"children\": [", tb->out);
+ }
+ /* between parent and child is separator */
+ fputs(linesep(tb), tb->out);
+ tb->indent_last_sep = 1;
+ tb->indent++;
+ tb->termlines_used++;
+}
+
+void fput_children_close(struct libscols_table *tb)
+{
+ tb->indent--;
+
+ if (scols_table_is_json(tb)) {
+ fput_indent(tb);
+ fputc(']', tb->out);
+ fputs(linesep(tb), tb->out);
+ tb->indent_last_sep = 1;
+ }
+}
+
+void fput_line_open(struct libscols_table *tb)
+{
+ if (scols_table_is_json(tb)) {
+ fput_indent(tb);
+ fputc('{', tb->out);
+ tb->indent_last_sep = 0;
+ }
+ tb->indent++;
+}
+
+void fput_line_close(struct libscols_table *tb, int last, int last_in_table)
+{
+ tb->indent--;
+ if (scols_table_is_json(tb)) {
+ if (tb->indent_last_sep)
+ fput_indent(tb);
+ fputs(last ? "}" : "},", tb->out);
+ if (!tb->no_linesep)
+ fputs(linesep(tb), tb->out);
+
+ } else if (tb->no_linesep == 0 && last_in_table == 0) {
+ fputs(linesep(tb), tb->out);
+ tb->termlines_used++;
+ }
+
+ tb->indent_last_sep = 1;
+}
diff --git a/src/utils/libsmartcols/src/grouping.c b/src/utils/libsmartcols/src/grouping.c
new file mode 100644
index 0000000..0b27cb2
--- /dev/null
+++ b/src/utils/libsmartcols/src/grouping.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2018 Karel Zak <kzak@redhat.com>
+ */
+#include "smartcolsP.h"
+
+/**
+ * SECTION: grouping
+ * @title: Grouping
+ * @short_description: lines grouing
+ *
+ * Lines groups manipulation API. The grouping API can be used to create M:N
+ * relations between lines and on tree-like output it prints extra chart to
+ * visualize these relations. The group has unlimited number of members and
+ * group childs. See libsmartcols/sample/grouping* for more details.
+ */
+
+/* Private API */
+void scols_ref_group(struct libscols_group *gr)
+{
+ if (gr)
+ gr->refcount++;
+}
+
+void scols_group_remove_children(struct libscols_group *gr)
+{
+ if (!gr)
+ return;
+
+ while (!list_empty(&gr->gr_children)) {
+ struct libscols_line *ln = list_entry(gr->gr_children.next,
+ struct libscols_line, ln_children);
+
+ DBG(GROUP, ul_debugobj(gr, "remove child"));
+ list_del_init(&ln->ln_children);
+ scols_ref_group(ln->parent_group);
+ ln->parent_group = NULL;
+ scols_unref_line(ln);
+ }
+}
+
+void scols_group_remove_members(struct libscols_group *gr)
+{
+ if (!gr)
+ return;
+
+ while (!list_empty(&gr->gr_members)) {
+ struct libscols_line *ln = list_entry(gr->gr_members.next,
+ struct libscols_line, ln_groups);
+
+ DBG(GROUP, ul_debugobj(gr, "remove member [%p]", ln));
+ list_del_init(&ln->ln_groups);
+
+ scols_unref_group(ln->group);
+ ln->group->nmembers++;
+ ln->group = NULL;
+
+ scols_unref_line(ln);
+ }
+}
+
+/* note group has to be already without members to deallocate */
+void scols_unref_group(struct libscols_group *gr)
+{
+ if (gr && --gr->refcount <= 0) {
+ DBG(GROUP, ul_debugobj(gr, "dealloc"));
+ scols_group_remove_children(gr);
+ list_del(&gr->gr_groups);
+ free(gr);
+ return;
+ }
+}
+
+
+static void groups_fix_members_order(struct libscols_line *ln)
+{
+ struct libscols_iter itr;
+ struct libscols_line *child;
+
+ if (ln->group) {
+ INIT_LIST_HEAD(&ln->ln_groups);
+ list_add_tail(&ln->ln_groups, &ln->group->gr_members);
+ DBG(GROUP, ul_debugobj(ln->group, "fixing member line=%p [%zu/%zu]",
+ ln, ln->group->nmembers,
+ list_count_entries(&ln->group->gr_members)));
+ }
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_line_next_child(ln, &itr, &child) == 0)
+ groups_fix_members_order(child);
+
+ /*
+ * We modify gr_members list, so is_last_group_member() does not have
+ * to provide reliable answer, we need to verify by list_count_entries().
+ */
+ if (ln->group
+ && is_last_group_member(ln)
+ && ln->group->nmembers == list_count_entries(&ln->group->gr_members)) {
+
+ DBG(GROUP, ul_debugobj(ln->group, "fixing childs"));
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_line_next_group_child(ln, &itr, &child) == 0)
+ groups_fix_members_order(child);
+ }
+}
+
+void scols_groups_fix_members_order(struct libscols_table *tb)
+{
+ struct libscols_iter itr;
+ struct libscols_line *ln;
+ struct libscols_group *gr;
+
+ /* remove all from groups lists */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_group(tb, &itr, &gr) == 0) {
+ while (!list_empty(&gr->gr_members)) {
+ struct libscols_line *line = list_entry(gr->gr_members.next,
+ struct libscols_line, ln_groups);
+ list_del_init(&line->ln_groups);
+ }
+ }
+
+ /* add again to the groups list in order we walk in tree */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->parent || ln->parent_group)
+ continue;
+ groups_fix_members_order(ln);
+ }
+
+ /* If group child is member of another group *
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_group(tb, &itr, &gr) == 0) {
+ struct libscols_iter xitr;
+ struct libscols_line *child;
+
+ scols_reset_iter(&xitr, SCOLS_ITER_FORWARD);
+ while (scols_line_next_group_child(ln, &xitr, &child) == 0)
+ groups_fix_members_order(child);
+ }
+ */
+}
+
+static inline const char *group_state_to_string(int state)
+{
+ static const char *grpstates[] = {
+ [SCOLS_GSTATE_NONE] = "none",
+ [SCOLS_GSTATE_FIRST_MEMBER] = "1st-member",
+ [SCOLS_GSTATE_MIDDLE_MEMBER] = "middle-member",
+ [SCOLS_GSTATE_LAST_MEMBER] = "last-member",
+ [SCOLS_GSTATE_MIDDLE_CHILD] = "middle-child",
+ [SCOLS_GSTATE_LAST_CHILD] = "last-child",
+ [SCOLS_GSTATE_CONT_MEMBERS] = "continue-members",
+ [SCOLS_GSTATE_CONT_CHILDREN] = "continue-children"
+ };
+
+ assert(state >= 0);
+ assert((size_t) state < ARRAY_SIZE(grpstates));
+
+ return grpstates[state];
+}
+/*
+static void grpset_debug(struct libscols_table *tb, struct libscols_line *ln)
+{
+ size_t i;
+
+ for (i = 0; i < tb->grpset_size; i++) {
+ if (tb->grpset[i]) {
+ struct libscols_group *gr = tb->grpset[i];
+
+ if (ln)
+ DBG(LINE, ul_debugobj(ln, "grpset[%zu]: %p %s", i,
+ gr, group_state_to_string(gr->state)));
+ else
+ DBG(LINE, ul_debug("grpset[%zu]: %p %s", i,
+ gr, group_state_to_string(gr->state)));
+ } else if (ln) {
+ DBG(LINE, ul_debugobj(ln, "grpset[%zu]: free", i));
+ } else
+ DBG(LINE, ul_debug("grpset[%zu]: free", i));
+ }
+}
+*/
+static int group_state_for_line(struct libscols_group *gr, struct libscols_line *ln)
+{
+ if (gr->state == SCOLS_GSTATE_NONE &&
+ (ln->group != gr || !is_first_group_member(ln)))
+ /*
+ * NONE is possible to translate to FIRST_MEMBER only, and only if
+ * line group matches with the current group.
+ */
+ return SCOLS_GSTATE_NONE;
+
+ if (ln->group != gr && ln->parent_group != gr) {
+ /* Not our line, continue */
+ if (gr->state == SCOLS_GSTATE_FIRST_MEMBER ||
+ gr->state == SCOLS_GSTATE_MIDDLE_MEMBER ||
+ gr->state == SCOLS_GSTATE_CONT_MEMBERS)
+ return SCOLS_GSTATE_CONT_MEMBERS;
+
+ if (gr->state == SCOLS_GSTATE_LAST_MEMBER ||
+ gr->state == SCOLS_GSTATE_MIDDLE_CHILD ||
+ gr->state == SCOLS_GSTATE_CONT_CHILDREN)
+ return SCOLS_GSTATE_CONT_CHILDREN;
+
+ } else if (ln->group == gr && is_first_group_member(ln)) {
+ return SCOLS_GSTATE_FIRST_MEMBER;
+
+ } else if (ln->group == gr && is_last_group_member(ln)) {
+ return SCOLS_GSTATE_LAST_MEMBER;
+
+ } else if (ln->group == gr && is_group_member(ln)) {
+ return SCOLS_GSTATE_MIDDLE_MEMBER;
+
+ } else if (ln->parent_group == gr && is_last_group_child(ln)) {
+ return SCOLS_GSTATE_LAST_CHILD;
+
+ } else if (ln->parent_group == gr && is_group_child(ln)) {
+ return SCOLS_GSTATE_MIDDLE_CHILD;
+ }
+
+ return SCOLS_GSTATE_NONE;
+}
+
+/*
+ * apply new @state to the chunk (addressed by @xx) of grpset used for the group (@gr)
+ */
+static void grpset_apply_group_state(struct libscols_group **xx, int state, struct libscols_group *gr)
+{
+ size_t i;
+
+ DBG(GROUP, ul_debugobj(gr, " applying state to grpset"));
+
+ /* gr->state holds the old state, @state is the new state
+ */
+ for (i = 0; i < SCOLS_GRPSET_CHUNKSIZ; i++)
+ xx[i] = state == SCOLS_GSTATE_NONE ? NULL : gr;
+
+ gr->state = state;
+}
+
+static struct libscols_group **grpset_locate_freespace(struct libscols_table *tb, int chunks, int prepend)
+{
+ size_t i, avail = 0;
+ struct libscols_group **tmp, **first = NULL;
+ const size_t wanted = chunks * SCOLS_GRPSET_CHUNKSIZ;
+
+ if (!tb->grpset_size)
+ prepend = 0;
+ /*
+ DBG(TAB, ul_debugobj(tb, "orig grpset:"));
+ grpset_debug(tb, NULL);
+ */
+ if (prepend) {
+ for (i = tb->grpset_size - 1; ; i--) {
+ if (tb->grpset[i] == NULL) {
+ first = &tb->grpset[i];
+ avail++;
+ } else
+ avail = 0;
+ if (avail == wanted)
+ goto done;
+ if (i == 0)
+ break;
+ }
+ } else {
+ for (i = 0; i < tb->grpset_size; i++) {
+ if (tb->grpset[i] == NULL) {
+ if (avail == 0)
+ first = &tb->grpset[i];
+ avail++;
+ } else
+ avail = 0;
+ if (avail == wanted)
+ goto done;
+ }
+ }
+
+ DBG(TAB, ul_debugobj(tb, " realocate grpset [sz: old=%zu, new=%zu, new_chunks=%d]",
+ tb->grpset_size, tb->grpset_size + wanted, chunks));
+
+ tmp = realloc(tb->grpset, (tb->grpset_size + wanted) * sizeof(struct libscols_group *));
+ if (!tmp)
+ return NULL;
+
+ tb->grpset = tmp;
+
+ if (prepend) {
+ DBG(TAB, ul_debugobj(tb, " prepending free space"));
+ char *dest = (char *) tb->grpset;
+
+ memmove( dest + (wanted * sizeof(struct libscols_group *)),
+ tb->grpset,
+ tb->grpset_size * sizeof(struct libscols_group *));
+ first = tb->grpset;
+ } else {
+ first = tb->grpset + tb->grpset_size;
+ }
+
+ memset(first, 0, wanted * sizeof(struct libscols_group *));
+ tb->grpset_size += wanted;
+
+done:
+ /*
+ DBG(TAB, ul_debugobj(tb, "new grpset:"));
+ grpset_debug(tb, NULL);
+ */
+ return first;
+}
+
+static struct libscols_group **grpset_locate_group(struct libscols_table *tb, struct libscols_group *gr)
+{
+ size_t i;
+
+ for (i = 0; i < tb->grpset_size; i++) {
+ if (gr == tb->grpset[i])
+ return &tb->grpset[i];
+ }
+
+ return NULL;
+}
+
+
+static int grpset_update(struct libscols_table *tb, struct libscols_line *ln, struct libscols_group *gr)
+{
+ struct libscols_group **xx;
+ int state;
+
+ DBG(LINE, ul_debugobj(ln, " group [%p] grpset update [grpset size=%zu]", gr, tb->grpset_size));
+
+ /* new state, note that gr->state still holds the original state */
+ state = group_state_for_line(gr, ln);
+ DBG(LINE, ul_debugobj(ln, " state %s --> %s",
+ group_state_to_string(gr->state),
+ group_state_to_string(state)));
+
+ if (state == SCOLS_GSTATE_FIRST_MEMBER && gr->state != SCOLS_GSTATE_NONE) {
+ DBG(LINE, ul_debugobj(ln, "wrong group initialization (%s)", group_state_to_string(gr->state)));
+ abort();
+ }
+ if (state != SCOLS_GSTATE_NONE && gr->state == SCOLS_GSTATE_LAST_CHILD) {
+ DBG(LINE, ul_debugobj(ln, "wrong group termination (%s)", group_state_to_string(gr->state)));
+ abort();
+ }
+ if (gr->state == SCOLS_GSTATE_LAST_MEMBER &&
+ !(state == SCOLS_GSTATE_LAST_CHILD ||
+ state == SCOLS_GSTATE_CONT_CHILDREN ||
+ state == SCOLS_GSTATE_MIDDLE_CHILD ||
+ state == SCOLS_GSTATE_NONE)) {
+ DBG(LINE, ul_debugobj(ln, "wrong group member->child order"));
+ abort();
+ }
+
+ /* should not happen; probably wrong line... */
+ if (gr->state == SCOLS_GSTATE_NONE && state == SCOLS_GSTATE_NONE)
+ return 0;
+
+ /* locate place in grpset where we draw the group */
+ if (!tb->grpset || gr->state == SCOLS_GSTATE_NONE)
+ xx = grpset_locate_freespace(tb, 1, 1);
+ else
+ xx = grpset_locate_group(tb, gr);
+ if (!xx) {
+ DBG(LINE, ul_debugobj(ln, "failed to locate group or reallocate grpset"));
+ return -ENOMEM;
+ }
+
+ grpset_apply_group_state(xx, state, gr);
+ /*ON_DBG(LINE, grpset_debug(tb, ln));*/
+ return 0;
+}
+
+static int grpset_update_active_groups(struct libscols_table *tb, struct libscols_line *ln)
+{
+ int rc = 0;
+ size_t i;
+ struct libscols_group *last = NULL;
+
+ DBG(LINE, ul_debugobj(ln, " update for active groups"));
+
+ for (i = 0; i < tb->grpset_size; i++) {
+ struct libscols_group *gr = tb->grpset[i];
+
+ if (!gr || last == gr)
+ continue;
+ last = gr;
+ rc = grpset_update(tb, ln, gr);
+ if (rc)
+ break;
+ }
+
+ DBG(LINE, ul_debugobj(ln, " <- active groups updated [rc=%d]", rc));
+ return rc;
+}
+
+int scols_groups_update_grpset(struct libscols_table *tb, struct libscols_line *ln)
+{
+ int rc = 0;
+
+ DBG(LINE, ul_debugobj(ln, " grpset update [line: group=%p, parent_group=%p",
+ ln->group, ln->parent_group));
+
+ rc = grpset_update_active_groups(tb, ln);
+ if (!rc && ln->group && ln->group->state == SCOLS_GSTATE_NONE) {
+ DBG(LINE, ul_debugobj(ln, " introduce a new group"));
+ rc = grpset_update(tb, ln, ln->group);
+ }
+ return rc;
+}
+
+void scols_groups_reset_state(struct libscols_table *tb)
+{
+ struct libscols_iter itr;
+ struct libscols_group *gr;
+
+ DBG(TAB, ul_debugobj(tb, "reset groups states"));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_group(tb, &itr, &gr) == 0) {
+ DBG(GROUP, ul_debugobj(gr, " reset to NONE"));
+ gr->state = SCOLS_GSTATE_NONE;
+ }
+
+ if (tb->grpset) {
+ DBG(TAB, ul_debugobj(tb, " zeroize grpset"));
+ memset(tb->grpset, 0, tb->grpset_size * sizeof(struct libscols_group *));
+ }
+ tb->ngrpchlds_pending = 0;
+}
+
+static void add_member(struct libscols_group *gr, struct libscols_line *ln)
+{
+ DBG(GROUP, ul_debugobj(gr, "add member %p", ln));
+
+ ln->group = gr;
+ gr->nmembers++;
+ scols_ref_group(gr);
+
+ INIT_LIST_HEAD(&ln->ln_groups);
+ list_add_tail(&ln->ln_groups, &gr->gr_members);
+ scols_ref_line(ln);
+}
+
+/*
+ * Returns first group which is ready to print group children.
+ *
+ * This function scans grpset[] in backward order and returns first group
+ * with SCOLS_GSTATE_CONT_CHILDREN or SCOLS_GSTATE_LAST_MEMBER state.
+ */
+struct libscols_group *scols_grpset_get_printable_children(struct libscols_table *tb)
+{
+ size_t i;
+
+ for (i = tb->grpset_size; i > 0; i -= SCOLS_GRPSET_CHUNKSIZ) {
+ struct libscols_group *gr = tb->grpset[i-1];
+
+ if (gr == NULL)
+ continue;
+ if (gr->state == SCOLS_GSTATE_CONT_CHILDREN ||
+ gr->state == SCOLS_GSTATE_LAST_MEMBER)
+ return gr;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * scols_table_group_lines:
+ * @tb: a pointer to a struct libscols_table instance
+ * @ln: new group member
+ * @member: group member
+ * @id: group identifier (unused, not implemented yet), use zero.
+ *
+ * This function add line @ln to group of lines represented by @member. If the
+ * group is not yet defined (@member is not member of any group) than a new one
+ * is allocated.
+ *
+ * The @ln maybe a NULL -- in this case only a new group is allocated if not
+ * defined yet.
+ *
+ * Note that the same line cannot be member of more groups (not implemented
+ * yet). The child of any group can be member of another group.
+ *
+ * The @id is not used for now, use 0. The plan is to use it to support
+ * multi-group membership in future.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_table_group_lines( struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_line *member,
+ __attribute__((__unused__)) int id)
+{
+ struct libscols_group *gr = NULL;
+
+ if (!tb || !member) {
+ DBG(GROUP, ul_debugobj(gr, "failed group lines (no table or member)"));
+ return -EINVAL;
+ }
+ if (ln) {
+ if (ln->group && !member->group) {
+ DBG(GROUP, ul_debugobj(gr, "failed group lines (new group, line member of another)"));
+ return -EINVAL;
+ }
+ if (ln->group && member->group && ln->group != member->group) {
+ DBG(GROUP, ul_debugobj(gr, "failed group lines (groups mismatch bwteen member and line"));
+ return -EINVAL;
+ }
+ }
+
+ gr = member->group;
+
+ /* create a new group */
+ if (!gr) {
+ gr = calloc(1, sizeof(*gr));
+ if (!gr)
+ return -ENOMEM;
+ DBG(GROUP, ul_debugobj(gr, "alloc"));
+ gr->refcount = 1;
+ INIT_LIST_HEAD(&gr->gr_members);
+ INIT_LIST_HEAD(&gr->gr_children);
+ INIT_LIST_HEAD(&gr->gr_groups);
+
+ /* add group to the table */
+ list_add_tail(&gr->gr_groups, &tb->tb_groups);
+
+ /* add the first member */
+ add_member(gr, member);
+ }
+
+ /* add to group */
+ if (ln && !ln->group)
+ add_member(gr, ln);
+
+ return 0;
+}
+
+/**
+ * scols_line_link_group:
+ * @ln: line instance
+ * @member: group member
+ * @id: group identifier (unused, not implemented yet))
+ *
+ * Define @ln as child of group represented by group @member. The line @ln
+ * cannot be child of any other line. It's possible to create group->child or
+ * parent->child relationship, but no both for the same line (child).
+ *
+ * The @id is not used for now, use 0. The plan is to use it to support
+ * multi-group membership in future.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_line_link_group(struct libscols_line *ln, struct libscols_line *member,
+ __attribute__((__unused__)) int id)
+{
+ if (!ln || !member || !member->group || ln->parent)
+ return -EINVAL;
+
+ if (!list_empty(&ln->ln_children))
+ return -EINVAL;
+
+ DBG(GROUP, ul_debugobj(member->group, "add child"));
+
+ list_add_tail(&ln->ln_children, &member->group->gr_children);
+ scols_ref_line(ln);
+
+ ln->parent_group = member->group;
+ scols_ref_group(member->group);
+
+ return 0;
+}
diff --git a/src/utils/libsmartcols/src/init.c b/src/utils/libsmartcols/src/init.c
new file mode 100644
index 0000000..dfd7510
--- /dev/null
+++ b/src/utils/libsmartcols/src/init.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: init
+ * @title: Library initialization
+ * @short_description: initialize debugging
+ *
+ * The library debug stuff.
+ */
+
+#include <stdarg.h>
+
+#include "smartcolsP.h"
+
+UL_DEBUG_DEFINE_MASK(libsmartcols);
+UL_DEBUG_DEFINE_MASKNAMES(libsmartcols) =
+{
+ { "all", SCOLS_DEBUG_ALL, "info about all subsystems" },
+ { "buff", SCOLS_DEBUG_BUFF, "output buffer utils" },
+ { "cell", SCOLS_DEBUG_CELL, "table cell utils" },
+ { "col", SCOLS_DEBUG_COL, "cols utils" },
+ { "help", SCOLS_DEBUG_HELP, "this help" },
+ { "group", SCOLS_DEBUG_GROUP, "lines grouping utils" },
+ { "line", SCOLS_DEBUG_LINE, "table line utils" },
+ { "tab", SCOLS_DEBUG_TAB, "table utils" },
+ { NULL, 0, NULL }
+};
+
+/**
+ * scols_init_debug:
+ * @mask: debug mask (0xffff to enable full debugging)
+ *
+ * If the @mask is not specified, then this function reads
+ * the LIBSMARTCOLS_DEBUG environment variable to get the mask.
+ *
+ * Already initialized debugging stuff cannot be changed. Calling
+ * this function twice has no effect.
+ */
+void scols_init_debug(int mask)
+{
+ if (libsmartcols_debug_mask)
+ return;
+
+ __UL_INIT_DEBUG_FROM_ENV(libsmartcols, SCOLS_DEBUG_, mask, LIBSMARTCOLS_DEBUG);
+
+ if (libsmartcols_debug_mask != SCOLS_DEBUG_INIT
+ && libsmartcols_debug_mask != (SCOLS_DEBUG_HELP|SCOLS_DEBUG_INIT)) {
+ const char *ver = NULL;
+
+ scols_get_library_version(&ver);
+
+ DBG(INIT, ul_debug("library debug mask: 0x%04x", libsmartcols_debug_mask));
+ DBG(INIT, ul_debug("library version: %s", ver));
+ }
+ ON_DBG(HELP, ul_debug_print_masks("LIBSMARTCOLS_DEBUG",
+ UL_DEBUG_MASKNAMES(libsmartcols)));
+}
diff --git a/src/utils/libsmartcols/src/iter.c b/src/utils/libsmartcols/src/iter.c
new file mode 100644
index 0000000..91cc080
--- /dev/null
+++ b/src/utils/libsmartcols/src/iter.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: iter
+ * @title: Iterator
+ * @short_description: unified iterator
+ *
+ * The iterator keeps the direction and the last position
+ * for access to the internal library tables/lists.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_iter:
+ * @direction: SCOLS_INTER_{FOR,BACK}WARD direction
+ *
+ * Returns: newly allocated generic libmount iterator.
+ */
+struct libscols_iter *scols_new_iter(int direction)
+{
+ struct libscols_iter *itr = calloc(1, sizeof(*itr));
+ if (!itr)
+ return NULL;
+ itr->direction = direction;
+ return itr;
+}
+
+/**
+ * scols_free_iter:
+ * @itr: iterator pointer
+ *
+ * Deallocates the iterator.
+ */
+void scols_free_iter(struct libscols_iter *itr)
+{
+ free(itr);
+}
+
+/**
+ * scols_reset_iter:
+ * @itr: iterator pointer
+ * @direction: SCOLS_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
+ *
+ * Resets the iterator.
+ */
+void scols_reset_iter(struct libscols_iter *itr, int direction)
+{
+ if (direction == -1)
+ direction = itr->direction;
+
+ memset(itr, 0, sizeof(*itr));
+ itr->direction = direction;
+}
+
+/**
+ * scols_iter_get_direction:
+ * @itr: iterator pointer
+ *
+ * Returns: SCOLS_INTER_{FOR,BACK}WARD
+ */
+int scols_iter_get_direction(const struct libscols_iter *itr)
+{
+ return itr->direction;
+}
diff --git a/src/utils/libsmartcols/src/libsmartcols.h b/src/utils/libsmartcols/src/libsmartcols.h
new file mode 100644
index 0000000..5714bfa
--- /dev/null
+++ b/src/utils/libsmartcols/src/libsmartcols.h
@@ -0,0 +1,329 @@
+/*
+ * Prints table or tree.
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#ifndef _LIBSMARTCOLS_H
+#define _LIBSMARTCOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/**
+ * libscols_iter:
+ *
+ * Generic iterator
+ */
+struct libscols_iter;
+
+/**
+ * libscols_symbols:
+ *
+ * Symbol groups for printing tree hierarchies
+ */
+struct libscols_symbols;
+
+/**
+ * libscols_cell:
+ *
+ * A cell - the smallest library object
+ */
+struct libscols_cell;
+
+/**
+ * libscols_line:
+ *
+ * A line - an array of cells
+ */
+struct libscols_line;
+
+/**
+ * libscols_table:
+ *
+ * A table - The most abstract object, encapsulating lines, columns, symbols and cells
+ */
+struct libscols_table;
+
+/**
+ * libscols_column:
+ *
+ * A column - defines the number of columns and column names
+ */
+struct libscols_column;
+
+/* iter.c */
+enum {
+
+ SCOLS_ITER_FORWARD = 0,
+ SCOLS_ITER_BACKWARD
+};
+
+/*
+ * Column flags
+ */
+enum {
+ SCOLS_FL_TRUNC = (1 << 0), /* truncate fields data if necessary */
+ SCOLS_FL_TREE = (1 << 1), /* use tree "ascii art" */
+ SCOLS_FL_RIGHT = (1 << 2), /* align to the right */
+ SCOLS_FL_STRICTWIDTH = (1 << 3), /* don't reduce width if column is empty */
+ SCOLS_FL_NOEXTREMES = (1 << 4), /* ignore extreme fields when count column width*/
+ SCOLS_FL_HIDDEN = (1 << 5), /* maintain data, but don't print */
+ SCOLS_FL_WRAP = (1 << 6) /* wrap long lines to multi-line cells */
+};
+
+/*
+ * Column JSON types
+ */
+enum {
+ SCOLS_JSON_STRING = 0, /* default */
+ SCOLS_JSON_NUMBER = 1,
+ SCOLS_JSON_BOOLEAN = 2
+};
+
+/*
+ * Cell flags, see scols_cell_set_flags() before use
+ */
+enum {
+ /* alignment evaluated in order: right,center,left */
+ SCOLS_CELL_FL_LEFT = 0,
+ SCOLS_CELL_FL_CENTER = (1 << 0),
+ SCOLS_CELL_FL_RIGHT = (1 << 1)
+};
+
+extern struct libscols_iter *scols_new_iter(int direction);
+extern void scols_free_iter(struct libscols_iter *itr);
+extern void scols_reset_iter(struct libscols_iter *itr, int direction);
+extern int scols_iter_get_direction(const struct libscols_iter *itr);
+
+/* init.c */
+extern void scols_init_debug(int mask);
+
+/* version.c */
+extern int scols_parse_version_string(const char *ver_string);
+extern int scols_get_library_version(const char **ver_string);
+
+/* symbols.c */
+extern struct libscols_symbols *scols_new_symbols(void);
+extern void scols_ref_symbols(struct libscols_symbols *sy);
+extern void scols_unref_symbols(struct libscols_symbols *sy);
+extern struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sy);
+extern int scols_symbols_set_branch(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_vertical(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_right(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_title_padding(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_cell_padding(struct libscols_symbols *sy, const char *str);
+
+extern int scols_symbols_set_group_vertical(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_horizontal(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_first_member(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_last_member(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_middle_member(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_last_child(struct libscols_symbols *sy, const char *str);
+extern int scols_symbols_set_group_middle_child(struct libscols_symbols *sy, const char *str);
+
+/* cell.c */
+extern int scols_reset_cell(struct libscols_cell *ce);
+extern int scols_cell_copy_content(struct libscols_cell *dest,
+ const struct libscols_cell *src);
+extern int scols_cell_set_data(struct libscols_cell *ce, const char *data);
+extern int scols_cell_refer_data(struct libscols_cell *ce, char *data);
+extern const char *scols_cell_get_data(const struct libscols_cell *ce);
+extern int scols_cell_set_color(struct libscols_cell *ce, const char *color);
+extern const char *scols_cell_get_color(const struct libscols_cell *ce);
+
+extern int scols_cell_set_flags(struct libscols_cell *ce, int flags);
+extern int scols_cell_get_flags(const struct libscols_cell *ce);
+extern int scols_cell_get_alignment(const struct libscols_cell *ce);
+
+extern void *scols_cell_get_userdata(struct libscols_cell *ce);
+extern int scols_cell_set_userdata(struct libscols_cell *ce, void *data);
+
+extern int scols_cmpstr_cells(struct libscols_cell *a,
+ struct libscols_cell *b, void *data);
+/* column.c */
+extern int scols_column_is_tree(const struct libscols_column *cl);
+extern int scols_column_is_trunc(const struct libscols_column *cl);
+extern int scols_column_is_right(const struct libscols_column *cl);
+extern int scols_column_is_strict_width(const struct libscols_column *cl);
+extern int scols_column_is_hidden(const struct libscols_column *cl);
+extern int scols_column_is_noextremes(const struct libscols_column *cl);
+extern int scols_column_is_wrap(const struct libscols_column *cl);
+extern int scols_column_is_customwrap(const struct libscols_column *cl);
+
+extern size_t scols_column_get_width(const struct libscols_column *cl);
+
+extern int scols_column_set_safechars(struct libscols_column *cl, const char *safe);
+extern const char *scols_column_get_safechars(const struct libscols_column *cl);
+
+extern int scols_column_set_json_type(struct libscols_column *cl, int type);
+extern int scols_column_get_json_type(const struct libscols_column *cl);
+
+extern int scols_column_set_flags(struct libscols_column *cl, int flags);
+extern int scols_column_get_flags(const struct libscols_column *cl);
+extern struct libscols_column *scols_new_column(void);
+extern void scols_ref_column(struct libscols_column *cl);
+extern void scols_unref_column(struct libscols_column *cl);
+extern struct libscols_column *scols_copy_column(const struct libscols_column *cl);
+extern int scols_column_set_whint(struct libscols_column *cl, double whint);
+extern double scols_column_get_whint(const struct libscols_column *cl);
+extern struct libscols_cell *scols_column_get_header(struct libscols_column *cl);
+extern int scols_column_set_color(struct libscols_column *cl, const char *color);
+extern const char *scols_column_get_color(const struct libscols_column *cl);
+extern struct libscols_table *scols_column_get_table(const struct libscols_column *cl);
+
+extern int scols_column_set_cmpfunc(struct libscols_column *cl,
+ int (*cmp)(struct libscols_cell *a,
+ struct libscols_cell *b, void *),
+ void *data);
+
+extern int scols_column_set_wrapfunc(struct libscols_column *cl,
+ size_t (*wrap_chunksize)(const struct libscols_column *,
+ const char *, void *),
+ char * (*wrap_nextchunk)(const struct libscols_column *,
+ char *, void *),
+ void *userdata);
+
+extern char *scols_wrapnl_nextchunk(const struct libscols_column *cl, char *data, void *userdata);
+extern size_t scols_wrapnl_chunksize(const struct libscols_column *cl, const char *data, void *userdata);
+
+/* line.c */
+extern struct libscols_line *scols_new_line(void);
+extern void scols_ref_line(struct libscols_line *ln);
+extern void scols_unref_line(struct libscols_line *ln);
+extern int scols_line_alloc_cells(struct libscols_line *ln, size_t n);
+extern void scols_line_free_cells(struct libscols_line *ln);
+extern int scols_line_set_userdata(struct libscols_line *ln, void *data);
+extern void *scols_line_get_userdata(struct libscols_line *ln);
+extern int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child);
+extern int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child);
+extern int scols_line_has_children(struct libscols_line *ln);
+extern int scols_line_is_ancestor(struct libscols_line *ln, struct libscols_line *parent);
+extern int scols_line_next_child(struct libscols_line *ln,
+ struct libscols_iter *itr, struct libscols_line **chld);
+extern struct libscols_line *scols_line_get_parent(const struct libscols_line *ln);
+extern int scols_line_set_color(struct libscols_line *ln, const char *color);
+extern const char *scols_line_get_color(const struct libscols_line *ln);
+extern size_t scols_line_get_ncells(const struct libscols_line *ln);
+extern struct libscols_cell *scols_line_get_cell(struct libscols_line *ln, size_t n);
+extern struct libscols_cell *scols_line_get_column_cell(
+ struct libscols_line *ln,
+ struct libscols_column *cl);
+extern int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data);
+extern int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data);
+extern int scols_line_set_column_data(struct libscols_line *ln, struct libscols_column *cl, const char *data);
+extern int scols_line_refer_column_data(struct libscols_line *ln, struct libscols_column *cl, char *data);
+extern struct libscols_line *scols_copy_line(const struct libscols_line *ln);
+
+/* table */
+extern int scols_table_colors_wanted(const struct libscols_table *tb);
+extern int scols_table_set_name(struct libscols_table *tb, const char *name);
+extern const char *scols_table_get_name(const struct libscols_table *tb);
+extern struct libscols_cell *scols_table_get_title(struct libscols_table *tb);
+extern int scols_table_is_raw(const struct libscols_table *tb);
+extern int scols_table_is_ascii(const struct libscols_table *tb);
+extern int scols_table_is_json(const struct libscols_table *tb);
+extern int scols_table_is_noheadings(const struct libscols_table *tb);
+extern int scols_table_is_header_repeat(const struct libscols_table *tb);
+extern int scols_table_is_empty(const struct libscols_table *tb);
+extern int scols_table_is_export(const struct libscols_table *tb);
+extern int scols_table_is_maxout(const struct libscols_table *tb);
+extern int scols_table_is_minout(const struct libscols_table *tb);
+extern int scols_table_is_nowrap(const struct libscols_table *tb);
+extern int scols_table_is_nolinesep(const struct libscols_table *tb);
+extern int scols_table_is_tree(const struct libscols_table *tb);
+extern int scols_table_is_noencoding(const struct libscols_table *tb);
+
+extern int scols_table_enable_colors(struct libscols_table *tb, int enable);
+extern int scols_table_enable_raw(struct libscols_table *tb, int enable);
+extern int scols_table_enable_ascii(struct libscols_table *tb, int enable);
+extern int scols_table_enable_json(struct libscols_table *tb, int enable);
+extern int scols_table_enable_noheadings(struct libscols_table *tb, int enable);
+extern int scols_table_enable_header_repeat(struct libscols_table *tb, int enable);
+extern int scols_table_enable_export(struct libscols_table *tb, int enable);
+extern int scols_table_enable_maxout(struct libscols_table *tb, int enable);
+extern int scols_table_enable_minout(struct libscols_table *tb, int enable);
+extern int scols_table_enable_nowrap(struct libscols_table *tb, int enable);
+extern int scols_table_enable_nolinesep(struct libscols_table *tb, int enable);
+extern int scols_table_enable_noencoding(struct libscols_table *tb, int enable);
+
+extern int scols_table_set_column_separator(struct libscols_table *tb, const char *sep);
+extern int scols_table_set_line_separator(struct libscols_table *tb, const char *sep);
+
+extern struct libscols_table *scols_new_table(void);
+extern void scols_ref_table(struct libscols_table *tb);
+extern void scols_unref_table(struct libscols_table *tb);
+extern int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl);
+extern int scols_table_remove_column(struct libscols_table *tb, struct libscols_column *cl);
+extern int scols_table_remove_columns(struct libscols_table *tb);
+extern int scols_table_move_column(struct libscols_table *tb, struct libscols_column *pre, struct libscols_column *cl);
+extern struct libscols_column *scols_table_new_column(struct libscols_table *tb, const char *name, double whint, int flags);
+extern int scols_table_next_column(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column **cl);
+extern int scols_table_set_columns_iter(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_column *cl);
+extern const char *scols_table_get_column_separator(const struct libscols_table *tb);
+extern const char *scols_table_get_line_separator(const struct libscols_table *tb);
+extern size_t scols_table_get_ncols(const struct libscols_table *tb);
+extern size_t scols_table_get_nlines(const struct libscols_table *tb);
+extern struct libscols_column *scols_table_get_column(struct libscols_table *tb, size_t n);
+extern int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln);
+extern int scols_table_remove_line(struct libscols_table *tb, struct libscols_line *ln);
+extern void scols_table_remove_lines(struct libscols_table *tb);
+extern int scols_table_next_line(struct libscols_table *tb, struct libscols_iter *itr, struct libscols_line **ln);
+extern struct libscols_line *scols_table_new_line(struct libscols_table *tb, struct libscols_line *parent);
+extern struct libscols_line *scols_table_get_line(struct libscols_table *tb, size_t n);
+extern struct libscols_table *scols_copy_table(struct libscols_table *tb);
+extern int scols_table_set_symbols(struct libscols_table *tb, struct libscols_symbols *sy);
+extern int scols_table_set_default_symbols(struct libscols_table *tb);
+extern struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb);
+
+extern int scols_table_set_stream(struct libscols_table *tb, FILE *stream);
+extern FILE *scols_table_get_stream(const struct libscols_table *tb);
+extern int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce);
+
+extern int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl);
+extern int scols_sort_table_by_tree(struct libscols_table *tb);
+/*
+ *
+ */
+enum {
+ SCOLS_TERMFORCE_AUTO = 0,
+ SCOLS_TERMFORCE_NEVER,
+ SCOLS_TERMFORCE_ALWAYS
+};
+extern int scols_table_set_termforce(struct libscols_table *tb, int force);
+extern int scols_table_get_termforce(const struct libscols_table *tb);
+extern int scols_table_set_termwidth(struct libscols_table *tb, size_t width);
+extern size_t scols_table_get_termwidth(const struct libscols_table *tb);
+extern int scols_table_set_termheight(struct libscols_table *tb, size_t height);
+extern size_t scols_table_get_termheight(const struct libscols_table *tb);
+
+
+/* table_print.c */
+extern int scols_print_table(struct libscols_table *tb);
+extern int scols_print_table_to_string(struct libscols_table *tb, char **data);
+
+extern int scols_table_print_range( struct libscols_table *tb,
+ struct libscols_line *start,
+ struct libscols_line *end);
+extern int scols_table_print_range_to_string( struct libscols_table *tb,
+ struct libscols_line *start,
+ struct libscols_line *end,
+ char **data);
+
+/* grouping.c */
+int scols_line_link_group(struct libscols_line *ln, struct libscols_line *member, int id);
+int scols_table_group_lines(struct libscols_table *tb, struct libscols_line *ln,
+ struct libscols_line *member, int id);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSMARTCOLS_H */
diff --git a/src/utils/libsmartcols/src/line.c b/src/utils/libsmartcols/src/line.c
new file mode 100644
index 0000000..351bed7
--- /dev/null
+++ b/src/utils/libsmartcols/src/line.c
@@ -0,0 +1,540 @@
+/*
+ * line.c - functions for table handling at the line level
+ *
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: line
+ * @title: Line
+ * @short_description: cells container, also keeps tree (parent->child) information
+ *
+ * An API to access and modify per-line data and information.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_line:
+ *
+ * Note that the line is allocated without cells, the cells will be allocated
+ * later when you add the line to the table. If you want to use the line
+ * without table then you have to explicitly allocate the cells by
+ * scols_line_alloc_cells().
+ *
+ * Returns: a pointer to a new struct libscols_line instance.
+ */
+struct libscols_line *scols_new_line(void)
+{
+ struct libscols_line *ln;
+
+ ln = calloc(1, sizeof(*ln));
+ if (!ln)
+ return NULL;
+
+ DBG(LINE, ul_debugobj(ln, "alloc"));
+ ln->refcount = 1;
+ INIT_LIST_HEAD(&ln->ln_lines);
+ INIT_LIST_HEAD(&ln->ln_children);
+ INIT_LIST_HEAD(&ln->ln_branch);
+ INIT_LIST_HEAD(&ln->ln_groups);
+ return ln;
+}
+
+/**
+ * scols_ref_line:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Increases the refcount of @ln.
+ */
+void scols_ref_line(struct libscols_line *ln)
+{
+ if (ln)
+ ln->refcount++;
+}
+
+/**
+ * scols_unref_line:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Decreases the refcount of @ln. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_line(struct libscols_line *ln)
+{
+ if (ln && --ln->refcount <= 0) {
+ DBG(CELL, ul_debugobj(ln, "dealloc"));
+ list_del(&ln->ln_lines);
+ list_del(&ln->ln_children);
+ list_del(&ln->ln_groups);
+ scols_unref_group(ln->group);
+ scols_line_free_cells(ln);
+ free(ln->color);
+ free(ln);
+ return;
+ }
+}
+
+/**
+ * scols_line_free_cells:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Frees the allocated cells referenced to by @ln.
+ */
+void scols_line_free_cells(struct libscols_line *ln)
+{
+ size_t i;
+
+ if (!ln || !ln->cells)
+ return;
+
+ DBG(LINE, ul_debugobj(ln, "free cells"));
+
+ for (i = 0; i < ln->ncells; i++)
+ scols_reset_cell(&ln->cells[i]);
+
+ free(ln->cells);
+ ln->ncells = 0;
+ ln->cells = NULL;
+}
+
+/**
+ * scols_line_alloc_cells:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: the number of elements
+ *
+ * Allocates space for @n cells. This function is optional,
+ * and libsmartcols automatically allocates necessary cells
+ * according to number of columns in the table when you add
+ * the line to the table. See scols_table_add_line().
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_alloc_cells(struct libscols_line *ln, size_t n)
+{
+ struct libscols_cell *ce;
+
+ if (!ln)
+ return -EINVAL;
+ if (ln->ncells == n)
+ return 0;
+
+ if (!n) {
+ scols_line_free_cells(ln);
+ return 0;
+ }
+
+ DBG(LINE, ul_debugobj(ln, "alloc %zu cells", n));
+
+ ce = realloc(ln->cells, n * sizeof(struct libscols_cell));
+ if (!ce)
+ return -errno;
+
+ if (n > ln->ncells)
+ memset(ce + ln->ncells, 0,
+ (n - ln->ncells) * sizeof(struct libscols_cell));
+
+ ln->cells = ce;
+ ln->ncells = n;
+ return 0;
+}
+
+int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn)
+{
+ struct libscols_cell ce;
+
+ if (!ln || newn >= ln->ncells || oldn >= ln->ncells)
+ return -EINVAL;
+ if (oldn == newn)
+ return 0;
+
+ DBG(LINE, ul_debugobj(ln, "move cells[%zu] -> cells[%zu]", oldn, newn));
+
+ /* remember data from old position */
+ memcpy(&ce, &ln->cells[oldn], sizeof(struct libscols_cell));
+
+ /* remove old position (move data behind oldn to oldn) */
+ if (oldn + 1 < ln->ncells)
+ memmove(ln->cells + oldn, ln->cells + oldn + 1,
+ (ln->ncells - oldn - 1) * sizeof(struct libscols_cell));
+
+ /* create a space for new position */
+ if (newn + 1 < ln->ncells)
+ memmove(ln->cells + newn + 1, ln->cells + newn,
+ (ln->ncells - newn - 1) * sizeof(struct libscols_cell));
+
+ /* copy original data to new position */
+ memcpy(&ln->cells[newn], &ce, sizeof(struct libscols_cell));
+ return 0;
+}
+
+/**
+ * scols_line_set_userdata:
+ * @ln: a pointer to a struct libscols_line instance
+ * @data: user data
+ *
+ * Binds @data to @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_userdata(struct libscols_line *ln, void *data)
+{
+ if (!ln)
+ return -EINVAL;
+ ln->userdata = data;
+ return 0;
+}
+
+/**
+ * scols_line_get_userdata:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: user data
+ */
+void *scols_line_get_userdata(struct libscols_line *ln)
+{
+ return ln->userdata;
+}
+
+/**
+ * scols_line_remove_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @child: a pointer to a struct libscols_line instance
+ *
+ * Removes @child as a child of @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_remove_child(struct libscols_line *ln, struct libscols_line *child)
+{
+ if (!ln || !child)
+ return -EINVAL;
+
+ DBG(LINE, ul_debugobj(ln, "remove child"));
+
+ list_del_init(&child->ln_children);
+ child->parent = NULL;
+ scols_unref_line(child);
+
+ scols_unref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_line_add_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @child: a pointer to a struct libscols_line instance
+ *
+ * Sets @child as a child of @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_add_child(struct libscols_line *ln, struct libscols_line *child)
+{
+ if (!ln || !child)
+ return -EINVAL;
+
+ DBG(LINE, ul_debugobj(ln, "add child"));
+ scols_ref_line(child);
+ scols_ref_line(ln);
+
+ /* unref old<->parent */
+ if (child->parent)
+ scols_line_remove_child(child->parent, child);
+
+ /* new reference from parent to child */
+ list_add_tail(&child->ln_children, &ln->ln_branch);
+
+ /* new reference from child to parent */
+ child->parent = ln;
+ return 0;
+}
+
+/**
+ * scols_line_get_parent:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: a pointer to @ln's parent, NULL in case it has no parent or if there was an error.
+ */
+struct libscols_line *scols_line_get_parent(const struct libscols_line *ln)
+{
+ return ln ? ln->parent : NULL;
+}
+
+/**
+ * scols_line_has_children:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: 1 if @ln has any children, otherwise 0.
+ */
+int scols_line_has_children(struct libscols_line *ln)
+{
+ return ln ? !list_empty(&ln->ln_branch) : 0;
+}
+
+/**
+ * scols_line_next_child:
+ * @ln: a pointer to a struct libscols_line instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @chld: a pointer to a pointer to a struct libscols_line instance
+ *
+ * Finds the next child and returns a pointer to it via @chld.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_next_child(struct libscols_line *ln,
+ struct libscols_iter *itr,
+ struct libscols_line **chld)
+{
+ int rc = 1;
+
+ if (!ln || !itr || !chld)
+ return -EINVAL;
+ *chld = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &ln->ln_branch);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* private API */
+int scols_line_next_group_child(struct libscols_line *ln,
+ struct libscols_iter *itr,
+ struct libscols_line **chld)
+{
+ int rc = 1;
+
+ if (!ln || !itr || !chld || !ln->group)
+ return -EINVAL;
+ *chld = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &ln->group->gr_children);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *chld, struct libscols_line, ln_children);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_line_is_ancestor:
+ * @ln: line
+ * @parent: potential parent
+ *
+ * The function is designed to detect circular dependencies between @ln and
+ * @parent. It checks if @ln is not any (grand) parent in the @parent's tree.
+ *
+ * Since: 2.30
+ *
+ * Returns: 0 or 1
+ */
+int scols_line_is_ancestor(struct libscols_line *ln, struct libscols_line *parent)
+{
+ while (parent) {
+ if (parent == ln)
+ return 1;
+ parent = scols_line_get_parent(parent);
+ };
+ return 0;
+}
+
+/**
+ * scols_line_set_color:
+ * @ln: a pointer to a struct libscols_line instance
+ * @color: color name or ESC sequence
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_color(struct libscols_line *ln, const char *color)
+{
+ if (color && isalnum(*color)) {
+ color = color_sequence_from_colorname(color);
+ if (!color)
+ return -EINVAL;
+ }
+ return strdup_to_struct_member(ln, color, color);
+}
+
+/**
+ * scols_line_get_color:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: @ln's color string, NULL in case of an error.
+ */
+const char *scols_line_get_color(const struct libscols_line *ln)
+{
+ return ln->color;
+}
+
+/**
+ * scols_line_get_ncells:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: number of cells
+ */
+size_t scols_line_get_ncells(const struct libscols_line *ln)
+{
+ return ln->ncells;
+}
+
+/**
+ * scols_line_get_cell:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: cell number to retrieve
+ *
+ * Returns: the @n-th cell in @ln, NULL in case of an error.
+ */
+struct libscols_cell *scols_line_get_cell(struct libscols_line *ln,
+ size_t n)
+{
+ if (!ln || n >= ln->ncells)
+ return NULL;
+ return &ln->cells[n];
+}
+
+/**
+ * scols_line_get_column_cell:
+ * @ln: a pointer to a struct libscols_line instance
+ * @cl: pointer to cell
+ *
+ * Like scols_line_get_cell() by cell is referenced by column.
+ *
+ * Returns: the @n-th cell in @ln, NULL in case of an error.
+ */
+struct libscols_cell *scols_line_get_column_cell(
+ struct libscols_line *ln,
+ struct libscols_column *cl)
+{
+ if (!ln || !cl)
+ return NULL;
+
+ return scols_line_get_cell(ln, cl->seqnum);
+}
+
+/**
+ * scols_line_set_data:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: number of the cell, whose data is to be set
+ * @data: actual data to set
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_set_data(struct libscols_line *ln, size_t n, const char *data)
+{
+ struct libscols_cell *ce = scols_line_get_cell(ln, n);
+
+ if (!ce)
+ return -EINVAL;
+ return scols_cell_set_data(ce, data);
+}
+
+/**
+ * scols_line_set_column_data:
+ * @ln: a pointer to a struct libscols_line instance
+ * @cl: column, whose data is to be set
+ * @data: actual data to set
+ *
+ * The same as scols_line_set_data() but cell is referenced by column object.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.28
+ */
+int scols_line_set_column_data(struct libscols_line *ln,
+ struct libscols_column *cl,
+ const char *data)
+{
+ return scols_line_set_data(ln, cl->seqnum, data);
+}
+
+/**
+ * scols_line_refer_data:
+ * @ln: a pointer to a struct libscols_line instance
+ * @n: number of the cell which will refer to @data
+ * @data: actual data to refer to
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_line_refer_data(struct libscols_line *ln, size_t n, char *data)
+{
+ struct libscols_cell *ce = scols_line_get_cell(ln, n);
+
+ if (!ce)
+ return -EINVAL;
+ return scols_cell_refer_data(ce, data);
+}
+
+/**
+ * scols_line_refer_column_data:
+ * @ln: a pointer to a struct libscols_line instance
+ * @cl: column, whose data is to be set
+ * @data: actual data to refer to
+ *
+ * The same as scols_line_refer_data() but cell is referenced by column object.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.28
+ */
+int scols_line_refer_column_data(struct libscols_line *ln,
+ struct libscols_column *cl,
+ char *data)
+{
+ return scols_line_refer_data(ln, cl->seqnum, data);
+}
+
+/**
+ * scols_copy_line:
+ * @ln: a pointer to a struct libscols_line instance
+ *
+ * Returns: A newly allocated copy of @ln, NULL in case of an error.
+ */
+struct libscols_line *scols_copy_line(const struct libscols_line *ln)
+{
+ struct libscols_line *ret;
+ size_t i;
+
+ if (!ln)
+ return NULL;
+
+ ret = scols_new_line();
+ if (!ret)
+ return NULL;
+ if (scols_line_set_color(ret, ln->color))
+ goto err;
+ if (scols_line_alloc_cells(ret, ln->ncells))
+ goto err;
+
+ ret->userdata = ln->userdata;
+ ret->ncells = ln->ncells;
+ ret->seqnum = ln->seqnum;
+
+ DBG(LINE, ul_debugobj(ln, "copy"));
+
+ for (i = 0; i < ret->ncells; ++i) {
+ if (scols_cell_copy_content(&ret->cells[i], &ln->cells[i]))
+ goto err;
+ }
+
+ return ret;
+err:
+ scols_unref_line(ret);
+ return NULL;
+}
diff --git a/src/utils/libsmartcols/src/print-api.c b/src/utils/libsmartcols/src/print-api.c
new file mode 100644
index 0000000..9a9f2df
--- /dev/null
+++ b/src/utils/libsmartcols/src/print-api.c
@@ -0,0 +1,211 @@
+#include "smartcolsP.h"
+
+/**
+ * scola_table_print_range:
+ * @tb: table
+ * @start: first printed line or NULL to print from the begin of the table
+ * @end: last printed line or NULL to print all from start.
+ *
+ * If the start is the first line in the table than prints table header too.
+ * The header is printed only once. This does not work for trees.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_print_range( struct libscols_table *tb,
+ struct libscols_line *start,
+ struct libscols_line *end)
+{
+ struct libscols_buffer *buf = NULL;
+ struct libscols_iter itr;
+ int rc;
+
+ if (scols_table_is_tree(tb))
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "printing range from API"));
+
+ rc = __scols_initialize_printing(tb, &buf);
+ if (rc)
+ return rc;
+
+ if (start) {
+ itr.direction = SCOLS_ITER_FORWARD;
+ itr.head = &tb->tb_lines;
+ itr.p = &start->ln_lines;
+ } else
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+
+ if (!start || itr.p == tb->tb_lines.next) {
+ rc = __scols_print_header(tb, buf);
+ if (rc)
+ goto done;
+ }
+
+ rc = __scols_print_range(tb, buf, &itr, end);
+done:
+ __scols_cleanup_printing(tb, buf);
+ return rc;
+}
+
+/**
+ * scols_table_print_range_to_string:
+ * @tb: table
+ * @start: first printed line or NULL to print from the beginning of the table
+ * @end: last printed line or NULL to print all from start.
+ * @data: pointer to the beginning of a memory area to print to
+ *
+ * The same as scols_table_print_range(), but prints to @data instead of
+ * stream.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+#ifdef HAVE_OPEN_MEMSTREAM
+int scols_table_print_range_to_string( struct libscols_table *tb,
+ struct libscols_line *start,
+ struct libscols_line *end,
+ char **data)
+{
+ FILE *stream, *old_stream;
+ size_t sz;
+ int rc;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "printing range to string"));
+
+ /* create a stream for output */
+ stream = open_memstream(data, &sz);
+ if (!stream)
+ return -ENOMEM;
+
+ old_stream = scols_table_get_stream(tb);
+ scols_table_set_stream(tb, stream);
+ rc = scols_table_print_range(tb, start, end);
+ fclose(stream);
+ scols_table_set_stream(tb, old_stream);
+
+ return rc;
+}
+#else
+int scols_table_print_range_to_string(
+ struct libscols_table *tb __attribute__((__unused__)),
+ struct libscols_line *start __attribute__((__unused__)),
+ struct libscols_line *end __attribute__((__unused__)),
+ char **data __attribute__((__unused__)))
+{
+ return -ENOSYS;
+}
+#endif
+
+static int do_print_table(struct libscols_table *tb, int *is_empty)
+{
+ int rc = 0;
+ struct libscols_buffer *buf = NULL;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "printing"));
+ if (is_empty)
+ *is_empty = 0;
+
+ if (list_empty(&tb->tb_columns)) {
+ DBG(TAB, ul_debugobj(tb, "error -- no columns"));
+ return -EINVAL;
+ }
+ if (list_empty(&tb->tb_lines)) {
+ DBG(TAB, ul_debugobj(tb, "ignore -- no lines"));
+ if (scols_table_is_json(tb)) {
+ fput_table_open(tb);
+ fput_table_close(tb);
+ } else if (is_empty)
+ *is_empty = 1;
+ return 0;
+ }
+
+ tb->header_printed = 0;
+ rc = __scols_initialize_printing(tb, &buf);
+ if (rc)
+ return rc;
+
+ fput_table_open(tb);
+
+ if (tb->format == SCOLS_FMT_HUMAN)
+ __scols_print_title(tb);
+
+ rc = __scols_print_header(tb, buf);
+ if (rc)
+ goto done;
+
+ if (scols_table_is_tree(tb))
+ rc = __scols_print_tree(tb, buf);
+ else
+ rc = __scols_print_table(tb, buf);
+
+ fput_table_close(tb);
+done:
+ __scols_cleanup_printing(tb, buf);
+ return rc;
+}
+
+/**
+ * scols_print_table:
+ * @tb: table
+ *
+ * Prints the table to the output stream and terminate by \n.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_print_table(struct libscols_table *tb)
+{
+ int empty = 0;
+ int rc = do_print_table(tb, &empty);
+
+ if (rc == 0 && !empty)
+ fputc('\n', tb->out);
+ return rc;
+}
+
+/**
+ * scols_print_table_to_string:
+ * @tb: table
+ * @data: pointer to the beginning of a memory area to print to
+ *
+ * Prints the table to @data.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+#ifdef HAVE_OPEN_MEMSTREAM
+int scols_print_table_to_string(struct libscols_table *tb, char **data)
+{
+ FILE *stream, *old_stream;
+ size_t sz;
+ int rc;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "printing to string"));
+
+ /* create a stream for output */
+ stream = open_memstream(data, &sz);
+ if (!stream)
+ return -ENOMEM;
+
+ old_stream = scols_table_get_stream(tb);
+ scols_table_set_stream(tb, stream);
+ rc = do_print_table(tb, NULL);
+ fclose(stream);
+ scols_table_set_stream(tb, old_stream);
+
+ return rc;
+}
+#else
+int scols_print_table_to_string(
+ struct libscols_table *tb __attribute__((__unused__)),
+ char **data __attribute__((__unused__)))
+{
+ return -ENOSYS;
+}
+#endif
diff --git a/src/utils/libsmartcols/src/print.c b/src/utils/libsmartcols/src/print.c
new file mode 100644
index 0000000..1172533
--- /dev/null
+++ b/src/utils/libsmartcols/src/print.c
@@ -0,0 +1,1089 @@
+/*
+ * table.c - functions handling the data at the table level
+ *
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: table_print
+ * @title: Table print
+ * @short_description: output functions
+ *
+ * Table output API.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+
+#include "mbsalign.h"
+#include "carefulputc.h"
+#include "smartcolsP.h"
+
+/* Fallback for symbols
+ *
+ * Note that by default library define all the symbols, but in case user does
+ * not define all symbols or if we extended the symbols struct then we need
+ * fallback to be more robust and backwardly compatible.
+ */
+#define titlepadding_symbol(tb) ((tb)->symbols->title_padding ? (tb)->symbols->title_padding : " ")
+#define branch_symbol(tb) ((tb)->symbols->tree_branch ? (tb)->symbols->tree_branch : "|-")
+#define vertical_symbol(tb) ((tb)->symbols->tree_vert ? (tb)->symbols->tree_vert : "| ")
+#define right_symbol(tb) ((tb)->symbols->tree_right ? (tb)->symbols->tree_right : "`-")
+
+#define grp_vertical_symbol(tb) ((tb)->symbols->group_vert ? (tb)->symbols->group_vert : "|")
+#define grp_horizontal_symbol(tb) ((tb)->symbols->group_horz ? (tb)->symbols->group_horz : "-")
+#define grp_m_first_symbol(tb) ((tb)->symbols->group_first_member ? (tb)->symbols->group_first_member : ",->")
+#define grp_m_last_symbol(tb) ((tb)->symbols->group_last_member ? (tb)->symbols->group_last_member : "\\->")
+#define grp_m_middle_symbol(tb) ((tb)->symbols->group_middle_member ? (tb)->symbols->group_middle_member : "|->")
+#define grp_c_middle_symbol(tb) ((tb)->symbols->group_middle_child ? (tb)->symbols->group_middle_child : "|-")
+#define grp_c_last_symbol(tb) ((tb)->symbols->group_last_child ? (tb)->symbols->group_last_child : "`-")
+
+#define cellpadding_symbol(tb) ((tb)->padding_debug ? "." : \
+ ((tb)->symbols->cell_padding ? (tb)->symbols->cell_padding: " "))
+
+#define want_repeat_header(tb) (!(tb)->header_repeat || (tb)->header_next <= (tb)->termlines_used)
+
+static int is_next_columns_empty(
+ struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln)
+{
+ struct libscols_iter itr;
+
+ if (!tb || !cl)
+ return 0;
+ if (is_last_column(cl))
+ return 1;
+ if (!ln)
+ return 0;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ scols_table_set_columns_iter(tb, &itr, cl);
+
+ /* skip current column */
+ scols_table_next_column(tb, &itr, &cl);
+
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ struct libscols_cell *ce;
+ const char *data = NULL;
+
+ if (scols_column_is_hidden(cl))
+ continue;
+ if (scols_column_is_tree(cl))
+ return 0;
+
+ ce = scols_line_get_cell(ln, cl->seqnum);
+ if (ce)
+ data = scols_cell_get_data(ce);
+ if (data && *data)
+ return 0;
+ }
+ return 1;
+}
+
+/* returns pointer to the end of used data */
+static int tree_ascii_art_to_buffer(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ const char *art;
+ int rc;
+
+ assert(ln);
+ assert(buf);
+
+ if (!ln->parent)
+ return 0;
+
+ rc = tree_ascii_art_to_buffer(tb, ln->parent, buf);
+ if (rc)
+ return rc;
+
+ if (is_last_child(ln))
+ art = " ";
+ else
+ art = vertical_symbol(tb);
+
+ return buffer_append_data(buf, art);
+}
+
+static int grpset_is_empty( struct libscols_table *tb,
+ size_t idx,
+ size_t *rest)
+{
+ size_t i;
+
+ for (i = idx; i < tb->grpset_size; i++) {
+ if (tb->grpset[i] == NULL) {
+ if (rest)
+ (*rest)++;
+ } else
+ return 0;
+ }
+ return 1;
+}
+
+static int groups_ascii_art_to_buffer( struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ int filled = 0;
+ size_t i, rest = 0;
+ const char *filler = cellpadding_symbol(tb);
+
+ if (!has_groups(tb))
+ return 0;
+
+ DBG(LINE, ul_debugobj(ln, "printing groups chart"));
+
+ if (tb->is_dummy_print)
+ return 0; /* allocate grpset[] only */
+
+ for (i = 0; i < tb->grpset_size; i += SCOLS_GRPSET_CHUNKSIZ) {
+ struct libscols_group *gr = tb->grpset[i];
+
+ if (!gr) {
+ buffer_append_ntimes(buf, SCOLS_GRPSET_CHUNKSIZ, cellpadding_symbol(tb));
+ continue;
+ }
+
+ switch (gr->state) {
+ case SCOLS_GSTATE_FIRST_MEMBER:
+ buffer_append_data(buf, grp_m_first_symbol(tb));
+ break;
+ case SCOLS_GSTATE_MIDDLE_MEMBER:
+ buffer_append_data(buf, grp_m_middle_symbol(tb));
+ break;
+ case SCOLS_GSTATE_LAST_MEMBER:
+ buffer_append_data(buf, grp_m_last_symbol(tb));
+ break;
+ case SCOLS_GSTATE_CONT_MEMBERS:
+ buffer_append_data(buf, grp_vertical_symbol(tb));
+ buffer_append_ntimes(buf, 2, filler);
+ break;
+ case SCOLS_GSTATE_MIDDLE_CHILD:
+ buffer_append_data(buf, filler);
+ buffer_append_data(buf, grp_c_middle_symbol(tb));
+ if (grpset_is_empty(tb, i + SCOLS_GRPSET_CHUNKSIZ, &rest)) {
+ buffer_append_ntimes(buf, rest+1, grp_horizontal_symbol(tb));
+ filled = 1;
+ }
+ filler = grp_horizontal_symbol(tb);
+ break;
+ case SCOLS_GSTATE_LAST_CHILD:
+ buffer_append_data(buf, cellpadding_symbol(tb));
+ buffer_append_data(buf, grp_c_last_symbol(tb));
+ if (grpset_is_empty(tb, i + SCOLS_GRPSET_CHUNKSIZ, &rest)) {
+ buffer_append_ntimes(buf, rest+1, grp_horizontal_symbol(tb));
+ filled = 1;
+ }
+ filler = grp_horizontal_symbol(tb);
+ break;
+ case SCOLS_GSTATE_CONT_CHILDREN:
+ buffer_append_data(buf, filler);
+ buffer_append_data(buf, grp_vertical_symbol(tb));
+ buffer_append_data(buf, filler);
+ break;
+ }
+
+ if (filled)
+ break;
+ }
+
+ if (!filled)
+ buffer_append_data(buf, filler);
+ return 0;
+}
+
+static int has_pending_data(struct libscols_table *tb)
+{
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ if (cl->pending_data)
+ return 1;
+ }
+ return 0;
+}
+
+/* print padding or ASCII-art instead of data of @cl */
+static void print_empty_cell(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ size_t bufsz)
+{
+ size_t len_pad = 0; /* in screen cells as opposed to bytes */
+
+ DBG(COL, ul_debugobj(cl, " printing empty cell"));
+
+ /* generate tree ASCII-art rather than padding */
+ if (ln && scols_column_is_tree(cl)) {
+ if (!ln->parent) {
+ /* only print symbols->vert if followed by child */
+ if (!list_empty(&ln->ln_branch)) {
+ fputs(vertical_symbol(tb), tb->out);
+ len_pad = scols_table_is_noencoding(tb) ?
+ mbs_width(vertical_symbol(tb)) :
+ mbs_safe_width(vertical_symbol(tb));
+ }
+ } else {
+ /* use the same draw function as though we were intending to draw an L-shape */
+ struct libscols_buffer *art = new_buffer(bufsz);
+ char *data;
+
+ if (art) {
+ /* whatever the rc, len_pad will be sensible */
+ tree_ascii_art_to_buffer(tb, ln, art);
+ if (!list_empty(&ln->ln_branch) && has_pending_data(tb))
+ buffer_append_data(art, vertical_symbol(tb));
+ data = buffer_get_safe_data(tb, art, &len_pad, NULL);
+ if (data && len_pad)
+ fputs(data, tb->out);
+ free_buffer(art);
+ }
+ }
+ }
+
+ /* minout -- don't fill */
+ if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+ return;
+
+ /* default -- fill except last column */
+ if (!scols_table_is_maxout(tb) && is_last_column(cl))
+ return;
+
+ /* fill rest of cell with space */
+ for(; len_pad < cl->width; ++len_pad)
+ fputs(cellpadding_symbol(tb), tb->out);
+
+ if (!is_last_column(cl))
+ fputs(colsep(tb), tb->out);
+}
+
+
+static const char *get_cell_color(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ struct libscols_cell *ce) /* optional */
+{
+ const char *color = NULL;
+
+ if (tb && tb->colors_wanted) {
+ if (ce)
+ color = ce->color;
+ if (ln && !color)
+ color = ln->color;
+ if (!color)
+ color = cl->color;
+ }
+ return color;
+}
+
+/* Fill the start of a line with padding (or with tree ascii-art).
+ *
+ * This is necessary after a long non-truncated column, as this requires the
+ * next column to be printed on the next line. For example (see 'DDD'):
+ *
+ * aaa bbb ccc ddd eee
+ * AAA BBB CCCCCCC
+ * DDD EEE
+ * ^^^^^^^^^^^^
+ * new line padding
+ */
+static void print_newline_padding(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ size_t bufsz)
+{
+ size_t i;
+
+ assert(tb);
+ assert(cl);
+
+ DBG(LINE, ul_debugobj(ln, "printing newline padding"));
+
+ fputs(linesep(tb), tb->out); /* line break */
+ tb->termlines_used++;
+
+ /* fill cells after line break */
+ for (i = 0; i <= (size_t) cl->seqnum; i++)
+ print_empty_cell(tb, scols_table_get_column(tb, i), ln, bufsz);
+}
+
+/*
+ * Pending data
+ *
+ * The first line in the multi-line cells (columns with SCOLS_FL_WRAP flag) is
+ * printed as usually and output is truncated to match column width.
+ *
+ * The rest of the long text is printed on next extra line(s). The extra lines
+ * don't exist in the table (not represented by libscols_line). The data for
+ * the extra lines are stored in libscols_column->pending_data_buf and the
+ * function print_line() adds extra lines until the buffer is not empty in all
+ * columns.
+ */
+
+/* set data that will be printed by extra lines */
+static int set_pending_data(struct libscols_column *cl, const char *data, size_t sz)
+{
+ char *p = NULL;
+
+ if (data && *data) {
+ DBG(COL, ul_debugobj(cl, "setting pending data"));
+ assert(sz);
+ p = strdup(data);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(cl->pending_data_buf);
+ cl->pending_data_buf = p;
+ cl->pending_data_sz = sz;
+ cl->pending_data = cl->pending_data_buf;
+ return 0;
+}
+
+/* the next extra line has been printed, move pending data cursor */
+static int step_pending_data(struct libscols_column *cl, size_t bytes)
+{
+ DBG(COL, ul_debugobj(cl, "step pending data %zu -= %zu", cl->pending_data_sz, bytes));
+
+ if (bytes >= cl->pending_data_sz)
+ return set_pending_data(cl, NULL, 0);
+
+ cl->pending_data += bytes;
+ cl->pending_data_sz -= bytes;
+ return 0;
+}
+
+/* print next pending data for the column @cl */
+static int print_pending_data(
+ struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ struct libscols_cell *ce)
+{
+ const char *color = get_cell_color(tb, cl, ln, ce);
+ size_t width = cl->width, bytes;
+ size_t len = width, i;
+ char *data;
+ char *nextchunk = NULL;
+
+ if (!cl->pending_data)
+ return 0;
+ if (!width)
+ return -EINVAL;
+
+ DBG(COL, ul_debugobj(cl, "printing pending data"));
+
+ data = strdup(cl->pending_data);
+ if (!data)
+ goto err;
+
+ if (scols_column_is_customwrap(cl)
+ && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
+ bytes = nextchunk - data;
+
+ len = scols_table_is_noencoding(tb) ?
+ mbs_nwidth(data, bytes) :
+ mbs_safe_nwidth(data, bytes, NULL);
+ } else
+ bytes = mbs_truncate(data, &len);
+
+ if (bytes == (size_t) -1)
+ goto err;
+
+ if (bytes)
+ step_pending_data(cl, bytes);
+
+ if (color)
+ fputs(color, tb->out);
+ fputs(data, tb->out);
+ if (color)
+ fputs(UL_COLOR_RESET, tb->out);
+ free(data);
+
+ /* minout -- don't fill */
+ if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+ return 0;
+
+ /* default -- fill except last column */
+ if (!scols_table_is_maxout(tb) && is_last_column(cl))
+ return 0;
+
+ /* fill rest of cell with space */
+ for(i = len; i < width; i++)
+ fputs(cellpadding_symbol(tb), tb->out);
+
+ if (!is_last_column(cl))
+ fputs(colsep(tb), tb->out);
+
+ return 0;
+err:
+ free(data);
+ return -errno;
+}
+
+static int print_data(struct libscols_table *tb,
+ struct libscols_column *cl,
+ struct libscols_line *ln, /* optional */
+ struct libscols_cell *ce, /* optional */
+ struct libscols_buffer *buf)
+{
+ size_t len = 0, i, width, bytes;
+ const char *color = NULL;
+ char *data, *nextchunk;
+ int is_last;
+
+ assert(tb);
+ assert(cl);
+
+ data = buffer_get_data(buf);
+ if (!data)
+ data = "";
+
+ is_last = is_last_column(cl);
+
+ switch (tb->format) {
+ case SCOLS_FMT_RAW:
+ fputs_nonblank(data, tb->out);
+ if (!is_last)
+ fputs(colsep(tb), tb->out);
+ return 0;
+
+ case SCOLS_FMT_EXPORT:
+ fprintf(tb->out, "%s=", scols_cell_get_data(&cl->header));
+ fputs_quoted(data, tb->out);
+ if (!is_last)
+ fputs(colsep(tb), tb->out);
+ return 0;
+
+ case SCOLS_FMT_JSON:
+ fputs_quoted_json_lower(scols_cell_get_data(&cl->header), tb->out);
+ fputs(":", tb->out);
+ switch (cl->json_type) {
+ case SCOLS_JSON_STRING:
+ if (!*data)
+ fputs("null", tb->out);
+ else
+ fputs_quoted_json(data, tb->out);
+ break;
+ case SCOLS_JSON_NUMBER:
+ if (!*data)
+ fputs("null", tb->out);
+ else
+ fputs(data, tb->out);
+ break;
+ case SCOLS_JSON_BOOLEAN:
+ fputs(!*data ? "false" :
+ *data == '0' ? "false" :
+ *data == 'N' || *data == 'n' ? "false" : "true",
+ tb->out);
+ break;
+ }
+ if (!is_last)
+ fputs(", ", tb->out);
+ return 0;
+
+ case SCOLS_FMT_HUMAN:
+ break; /* continue below */
+ }
+
+ color = get_cell_color(tb, cl, ln, ce);
+
+ /* Encode. Note that 'len' and 'width' are number of cells, not bytes.
+ */
+ data = buffer_get_safe_data(tb, buf, &len, scols_column_get_safechars(cl));
+ if (!data)
+ data = "";
+ bytes = strlen(data);
+ width = cl->width;
+
+ /* custom multi-line cell based */
+ if (*data && scols_column_is_customwrap(cl)
+ && (nextchunk = cl->wrap_nextchunk(cl, data, cl->wrapfunc_data))) {
+ set_pending_data(cl, nextchunk, bytes - (nextchunk - data));
+ bytes = nextchunk - data;
+
+ len = scols_table_is_noencoding(tb) ?
+ mbs_nwidth(data, bytes) :
+ mbs_safe_nwidth(data, bytes, NULL);
+ }
+
+ if (is_last
+ && len < width
+ && !scols_table_is_maxout(tb)
+ && !scols_column_is_right(cl))
+ width = len;
+
+ /* truncate data */
+ if (len > width && scols_column_is_trunc(cl)) {
+ len = width;
+ bytes = mbs_truncate(data, &len); /* updates 'len' */
+ }
+
+ /* standard multi-line cell */
+ if (len > width && scols_column_is_wrap(cl)
+ && !scols_column_is_customwrap(cl)) {
+ set_pending_data(cl, data, bytes);
+
+ len = width;
+ bytes = mbs_truncate(data, &len);
+ if (bytes != (size_t) -1 && bytes > 0)
+ step_pending_data(cl, bytes);
+ }
+
+ if (bytes == (size_t) -1) {
+ bytes = len = 0;
+ data = NULL;
+ }
+
+ if (data && *data) {
+ if (scols_column_is_right(cl)) {
+ if (color)
+ fputs(color, tb->out);
+ for (i = len; i < width; i++)
+ fputs(cellpadding_symbol(tb), tb->out);
+ fputs(data, tb->out);
+ if (color)
+ fputs(UL_COLOR_RESET, tb->out);
+ len = width;
+
+ } else if (color) {
+ char *p = data;
+ size_t art = buffer_get_safe_art_size(buf);
+
+ /* we don't want to colorize tree ascii art */
+ if (scols_column_is_tree(cl) && art && art < bytes) {
+ fwrite(p, 1, art, tb->out);
+ p += art;
+ }
+
+ fputs(color, tb->out);
+ fputs(p, tb->out);
+ fputs(UL_COLOR_RESET, tb->out);
+ } else
+ fputs(data, tb->out);
+ }
+
+ /* minout -- don't fill */
+ if (scols_table_is_minout(tb) && is_next_columns_empty(tb, cl, ln))
+ return 0;
+
+ /* default -- fill except last column */
+ if (!scols_table_is_maxout(tb) && is_last)
+ return 0;
+
+ /* fill rest of cell with space */
+ for(i = len; i < width; i++)
+ fputs(cellpadding_symbol(tb), tb->out);
+
+ if (len > width && !scols_column_is_trunc(cl)) {
+ DBG(COL, ul_debugobj(cl, "*** data len=%zu > column width=%zu", len, width));
+ print_newline_padding(tb, cl, ln, buffer_get_size(buf)); /* next column starts on next line */
+
+ } else if (!is_last)
+ fputs(colsep(tb), tb->out); /* columns separator */
+
+ return 0;
+}
+
+int __cell_to_buffer(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf)
+{
+ const char *data;
+ struct libscols_cell *ce;
+ int rc = 0;
+
+ assert(tb);
+ assert(ln);
+ assert(cl);
+ assert(buf);
+ assert(cl->seqnum <= tb->ncols);
+
+ buffer_reset_data(buf);
+
+ ce = scols_line_get_cell(ln, cl->seqnum);
+ data = ce ? scols_cell_get_data(ce) : NULL;
+
+ if (!scols_column_is_tree(cl))
+ return data ? buffer_set_data(buf, data) : 0;
+
+ /*
+ * Group stuff
+ */
+ if (!scols_table_is_json(tb) && cl->is_groups)
+ rc = groups_ascii_art_to_buffer(tb, ln, buf);
+
+ /*
+ * Tree stuff
+ */
+ if (!rc && ln->parent && !scols_table_is_json(tb)) {
+ rc = tree_ascii_art_to_buffer(tb, ln->parent, buf);
+
+ if (!rc && is_last_child(ln))
+ rc = buffer_append_data(buf, right_symbol(tb));
+ else if (!rc)
+ rc = buffer_append_data(buf, branch_symbol(tb));
+ }
+
+ if (!rc && (ln->parent || cl->is_groups) && !scols_table_is_json(tb))
+ buffer_set_art_index(buf);
+
+ if (!rc && data)
+ rc = buffer_append_data(buf, data);
+ return rc;
+}
+
+/*
+ * Prints data. Data can be printed in more formats (raw, NAME=xxx pairs), and
+ * control and non-printable characters can be encoded in the \x?? encoding.
+ */
+static int print_line(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_buffer *buf)
+{
+ int rc = 0, pending = 0;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ assert(ln);
+
+ DBG(LINE, ul_debugobj(ln, "printing line"));
+
+ /* regular line */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ rc = __cell_to_buffer(tb, ln, cl, buf);
+ if (rc == 0)
+ rc = print_data(tb, cl, ln,
+ scols_line_get_cell(ln, cl->seqnum),
+ buf);
+ if (rc == 0 && cl->pending_data)
+ pending = 1;
+ }
+
+ /* extra lines of the multi-line cells */
+ while (rc == 0 && pending) {
+ DBG(LINE, ul_debugobj(ln, "printing pending data"));
+ pending = 0;
+ fputs(linesep(tb), tb->out);
+ tb->termlines_used++;
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ if (cl->pending_data) {
+ rc = print_pending_data(tb, cl, ln, scols_line_get_cell(ln, cl->seqnum));
+ if (rc == 0 && cl->pending_data)
+ pending = 1;
+ } else
+ print_empty_cell(tb, cl, ln, buffer_get_size(buf));
+ }
+ }
+
+ return 0;
+}
+
+int __scols_print_title(struct libscols_table *tb)
+{
+ int rc, color = 0;
+ mbs_align_t align;
+ size_t width, len = 0, bufsz, titlesz;
+ char *title = NULL, *buf = NULL;
+
+ assert(tb);
+
+ if (!tb->title.data)
+ return 0;
+
+ DBG(TAB, ul_debugobj(tb, "printing title"));
+
+ /* encode data */
+ if (tb->no_encode) {
+ len = bufsz = strlen(tb->title.data) + 1;
+ buf = strdup(tb->title.data);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto done;
+ }
+ } else {
+ bufsz = mbs_safe_encode_size(strlen(tb->title.data)) + 1;
+ if (bufsz == 1) {
+ DBG(TAB, ul_debugobj(tb, "title is empty string -- ignore"));
+ return 0;
+ }
+ buf = malloc(bufsz);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (!mbs_safe_encode_to_buffer(tb->title.data, &len, buf, NULL) ||
+ !len || len == (size_t) -1) {
+ rc = -EINVAL;
+ goto done;
+ }
+ }
+
+ /* truncate and align */
+ width = tb->is_term ? tb->termwidth : 80;
+ titlesz = width + bufsz;
+
+ title = malloc(titlesz);
+ if (!title) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ switch (scols_cell_get_alignment(&tb->title)) {
+ case SCOLS_CELL_FL_RIGHT:
+ align = MBS_ALIGN_RIGHT;
+ break;
+ case SCOLS_CELL_FL_CENTER:
+ align = MBS_ALIGN_CENTER;
+ break;
+ case SCOLS_CELL_FL_LEFT:
+ default:
+ align = MBS_ALIGN_LEFT;
+ /*
+ * Don't print extra blank chars after the title if on left
+ * (that's same as we use for the last column in the table).
+ */
+ if (len < width
+ && !scols_table_is_maxout(tb)
+ && isblank(*titlepadding_symbol(tb)))
+ width = len;
+ break;
+
+ }
+
+ /* copy from buf to title and align to width with title_padding */
+ rc = mbsalign_with_padding(buf, title, titlesz,
+ &width, align,
+ 0, (int) *titlepadding_symbol(tb));
+
+ if (rc == -1) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ if (tb->colors_wanted && tb->title.color)
+ color = 1;
+ if (color)
+ fputs(tb->title.color, tb->out);
+
+ fputs(title, tb->out);
+
+ if (color)
+ fputs(UL_COLOR_RESET, tb->out);
+
+ fputc('\n', tb->out);
+ rc = 0;
+done:
+ free(buf);
+ free(title);
+ DBG(TAB, ul_debugobj(tb, "printing title done [rc=%d]", rc));
+ return rc;
+}
+
+int __scols_print_header(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ int rc = 0;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ assert(tb);
+
+ if ((tb->header_printed == 1 && tb->header_repeat == 0) ||
+ scols_table_is_noheadings(tb) ||
+ scols_table_is_export(tb) ||
+ scols_table_is_json(tb) ||
+ list_empty(&tb->tb_lines))
+ return 0;
+
+ DBG(TAB, ul_debugobj(tb, "printing header"));
+
+ /* set the width according to the size of the data */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+
+ buffer_reset_data(buf);
+
+ if (cl->is_groups
+ && scols_table_is_tree(tb) && scols_column_is_tree(cl)) {
+ size_t i;
+ for (i = 0; i < tb->grpset_size + 1; i++) {
+ rc = buffer_append_data(buf, " ");
+ if (rc)
+ break;
+ }
+ }
+ if (!rc)
+ rc = buffer_append_data(buf, scols_cell_get_data(&cl->header));
+ if (!rc)
+ rc = print_data(tb, cl, NULL, &cl->header, buf);
+ }
+
+ if (rc == 0) {
+ fputs(linesep(tb), tb->out);
+ tb->termlines_used++;
+ }
+
+ tb->header_printed = 1;
+ tb->header_next = tb->termlines_used + tb->termheight;
+ if (tb->header_repeat)
+ DBG(TAB, ul_debugobj(tb, "\tnext header: %zu [current=%zu, rc=%d]",
+ tb->header_next, tb->termlines_used, rc));
+ return rc;
+}
+
+
+int __scols_print_range(struct libscols_table *tb,
+ struct libscols_buffer *buf,
+ struct libscols_iter *itr,
+ struct libscols_line *end)
+{
+ int rc = 0;
+ struct libscols_line *ln;
+
+ assert(tb);
+ DBG(TAB, ul_debugobj(tb, "printing range"));
+
+ while (rc == 0 && scols_table_next_line(tb, itr, &ln) == 0) {
+
+ int last = scols_iter_is_last(itr);
+
+ fput_line_open(tb);
+ rc = print_line(tb, ln, buf);
+ fput_line_close(tb, last, last);
+
+ if (end && ln == end)
+ break;
+
+ if (!last && want_repeat_header(tb))
+ __scols_print_header(tb, buf);
+ }
+
+ return rc;
+
+}
+
+int __scols_print_table(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ struct libscols_iter itr;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ return __scols_print_range(tb, buf, &itr, NULL);
+}
+
+/* scols_walk_tree() callback to print tree line */
+static int print_tree_line(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl __attribute__((__unused__)),
+ void *data)
+{
+ struct libscols_buffer *buf = (struct libscols_buffer *) data;
+ int rc;
+
+ DBG(LINE, ul_debugobj(ln, " printing tree line"));
+
+ fput_line_open(tb);
+ rc = print_line(tb, ln, buf);
+ if (rc)
+ return rc;
+
+ if (has_children(ln))
+ fput_children_open(tb);
+
+ else {
+ int last_in_tree = scols_walk_is_last(tb, ln);
+ int last;
+
+ /* terminate all open last children for JSON */
+ if (scols_table_is_json(tb)) {
+ do {
+ last = (is_child(ln) && is_last_child(ln)) ||
+ (is_tree_root(ln) && is_last_tree_root(tb, ln));
+
+ fput_line_close(tb, last, last_in_tree);
+ if (last && is_child(ln))
+ fput_children_close(tb);
+
+ last_in_tree = 0;
+ ln = ln->parent;
+ } while(ln && last);
+
+ } else {
+ /* standard output */
+ last = (is_child(ln) && is_last_child(ln)) ||
+ (is_group_child(ln) && is_last_group_child(ln));
+
+ fput_line_close(tb, last, last_in_tree);
+ }
+ }
+
+ return 0;
+}
+
+int __scols_print_tree(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ assert(tb);
+ DBG(TAB, ul_debugobj(tb, "----printing-tree-----"));
+
+ return scols_walk_tree(tb, NULL, print_tree_line, (void *) buf);
+}
+
+static size_t strlen_line(struct libscols_line *ln)
+{
+ size_t i, sz = 0;
+
+ assert(ln);
+
+ for (i = 0; i < ln->ncells; i++) {
+ struct libscols_cell *ce = scols_line_get_cell(ln, i);
+ const char *data = ce ? scols_cell_get_data(ce) : NULL;
+
+ sz += data ? strlen(data) : 0;
+ }
+
+ return sz;
+}
+
+void __scols_cleanup_printing(struct libscols_table *tb, struct libscols_buffer *buf)
+{
+ if (!tb)
+ return;
+
+ free_buffer(buf);
+
+ if (tb->priv_symbols) {
+ scols_table_set_symbols(tb, NULL);
+ tb->priv_symbols = 0;
+ }
+}
+
+int __scols_initialize_printing(struct libscols_table *tb, struct libscols_buffer **buf)
+{
+ size_t bufsz, extra_bufsz = 0;
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+ int rc;
+
+ DBG(TAB, ul_debugobj(tb, "initialize printing"));
+ *buf = NULL;
+
+ if (!tb->symbols) {
+ rc = scols_table_set_default_symbols(tb);
+ if (rc)
+ goto err;
+ tb->priv_symbols = 1;
+ } else
+ tb->priv_symbols = 0;
+
+ if (tb->format == SCOLS_FMT_HUMAN)
+ tb->is_term = tb->termforce == SCOLS_TERMFORCE_NEVER ? 0 :
+ tb->termforce == SCOLS_TERMFORCE_ALWAYS ? 1 :
+ isatty(STDOUT_FILENO);
+
+ if (tb->is_term) {
+ size_t width = (size_t) scols_table_get_termwidth(tb);
+
+ if (tb->termreduce > 0 && tb->termreduce < width) {
+ width -= tb->termreduce;
+ scols_table_set_termwidth(tb, width);
+ }
+ bufsz = width;
+ } else
+ bufsz = BUFSIZ;
+
+ if (!tb->is_term || tb->format != SCOLS_FMT_HUMAN || scols_table_is_tree(tb))
+ tb->header_repeat = 0;
+
+ /*
+ * Estimate extra space necessary for tree, JSON or another output
+ * decoration.
+ */
+ if (scols_table_is_tree(tb))
+ extra_bufsz += tb->nlines * strlen(vertical_symbol(tb));
+
+ switch (tb->format) {
+ case SCOLS_FMT_RAW:
+ extra_bufsz += tb->ncols; /* separator between columns */
+ break;
+ case SCOLS_FMT_JSON:
+ if (tb->format == SCOLS_FMT_JSON)
+ extra_bufsz += tb->nlines * 3; /* indentation */
+ /* fallthrough */
+ case SCOLS_FMT_EXPORT:
+ {
+ struct libscols_column *cl;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (scols_column_is_hidden(cl))
+ continue;
+ extra_bufsz += strlen(scols_cell_get_data(&cl->header)); /* data */
+ extra_bufsz += 2; /* separators */
+ }
+ break;
+ }
+ case SCOLS_FMT_HUMAN:
+ break;
+ }
+
+ /*
+ * Enlarge buffer if necessary, the buffer should be large enough to
+ * store line data and tree ascii art (or another decoration).
+ */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ size_t sz;
+
+ sz = strlen_line(ln) + extra_bufsz;
+ if (sz > bufsz)
+ bufsz = sz;
+ }
+
+ *buf = new_buffer(bufsz + 1); /* data + space for \0 */
+ if (!*buf) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * Make sure groups members are in the same orders as the tree
+ */
+ if (has_groups(tb) && scols_table_is_tree(tb))
+ scols_groups_fix_members_order(tb);
+
+ if (tb->format == SCOLS_FMT_HUMAN) {
+ rc = __scols_calculate(tb, *buf);
+ if (rc != 0)
+ goto err;
+ }
+
+ return 0;
+err:
+ __scols_cleanup_printing(tb, *buf);
+ return rc;
+}
+
diff --git a/src/utils/libsmartcols/src/smartcolsP.h b/src/utils/libsmartcols/src/smartcolsP.h
new file mode 100644
index 0000000..e36bb51
--- /dev/null
+++ b/src/utils/libsmartcols/src/smartcolsP.h
@@ -0,0 +1,468 @@
+/*
+ * smartcolsP.h - private library header file
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#ifndef _LIBSMARTCOLS_PRIVATE_H
+#define _LIBSMARTCOLS_PRIVATE_H
+
+#include "c.h"
+#include "list.h"
+#include "strutils.h"
+#include "color-names.h"
+#include "debug.h"
+
+#include "libsmartcols.h"
+
+/*
+ * Debug
+ */
+#define SCOLS_DEBUG_HELP (1 << 0)
+#define SCOLS_DEBUG_INIT (1 << 1)
+#define SCOLS_DEBUG_CELL (1 << 2)
+#define SCOLS_DEBUG_LINE (1 << 3)
+#define SCOLS_DEBUG_TAB (1 << 4)
+#define SCOLS_DEBUG_COL (1 << 5)
+#define SCOLS_DEBUG_BUFF (1 << 6)
+#define SCOLS_DEBUG_GROUP (1 << 7)
+#define SCOLS_DEBUG_ALL 0xFFFF
+
+UL_DEBUG_DECLARE_MASK(libsmartcols);
+#define DBG(m, x) __UL_DBG(libsmartcols, SCOLS_DEBUG_, m, x)
+#define ON_DBG(m, x) __UL_DBG_CALL(libsmartcols, SCOLS_DEBUG_, m, x)
+#define DBG_FLUSH __UL_DBG_FLUSH(libsmartcols, SCOLS_DEBUG_)
+
+#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(libsmartcols)
+#include "debugobj.h"
+
+/*
+ * Generic iterator
+ */
+struct libscols_iter {
+ struct list_head *p; /* current position */
+ struct list_head *head; /* start position */
+ int direction; /* SCOLS_ITER_{FOR,BACK}WARD */
+};
+
+/*
+ * Tree symbols
+ */
+struct libscols_symbols {
+ int refcount;
+
+ char *tree_branch;
+ char *tree_vert;
+ char *tree_right;
+
+ char *group_vert;
+ char *group_horz;
+ char *group_first_member;
+ char *group_last_member;
+ char *group_middle_member;
+ char *group_last_child;
+ char *group_middle_child;
+
+ char *title_padding;
+ char *cell_padding;
+};
+
+/*
+ * Table cells
+ */
+struct libscols_cell {
+ char *data;
+ char *color;
+ void *userdata;
+ int flags;
+};
+
+extern int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn);
+
+/*
+ * Table column
+ */
+struct libscols_column {
+ int refcount; /* reference counter */
+ size_t seqnum; /* column index */
+
+ size_t width; /* real column width */
+ size_t width_min; /* minimal width (usually header width) */
+ size_t width_max; /* maximal width */
+ size_t width_avg; /* average width, used to detect extreme fields */
+ size_t width_treeart; /* size of the tree ascii art */
+ double width_hint; /* hint (N < 1 is in percent of termwidth) */
+
+ size_t extreme_sum;
+ int extreme_count;
+
+ int json_type; /* SCOLS_JSON_* */
+
+ int flags;
+ char *color; /* default column color */
+ char *safechars; /* do not encode this bytes */
+
+ char *pending_data;
+ size_t pending_data_sz;
+ char *pending_data_buf;
+
+ int (*cmpfunc)(struct libscols_cell *,
+ struct libscols_cell *,
+ void *); /* cells comparison function */
+ void *cmpfunc_data;
+
+ size_t (*wrap_chunksize)(const struct libscols_column *,
+ const char *, void *);
+ char *(*wrap_nextchunk)(const struct libscols_column *,
+ char *, void *);
+ void *wrapfunc_data;
+
+
+ struct libscols_cell header;
+ struct list_head cl_columns;
+
+ struct libscols_table *table;
+
+ unsigned int is_extreme : 1, /* extreme width in the column */
+ is_groups : 1; /* print group chart */
+
+};
+
+#define colsep(tb) ((tb)->colsep ? (tb)->colsep : " ")
+#define linesep(tb) ((tb)->linesep ? (tb)->linesep : "\n")
+
+enum {
+ SCOLS_GSTATE_NONE = 0, /* not activate yet */
+ SCOLS_GSTATE_FIRST_MEMBER,
+ SCOLS_GSTATE_MIDDLE_MEMBER,
+ SCOLS_GSTATE_LAST_MEMBER,
+ SCOLS_GSTATE_MIDDLE_CHILD,
+ SCOLS_GSTATE_LAST_CHILD,
+ SCOLS_GSTATE_CONT_MEMBERS,
+ SCOLS_GSTATE_CONT_CHILDREN
+};
+
+/*
+ * Every group needs at least 3 columns
+ */
+#define SCOLS_GRPSET_CHUNKSIZ 3
+
+struct libscols_group {
+ int refcount;
+
+ size_t nmembers;
+
+ struct list_head gr_members; /* head of line->ln_group */
+ struct list_head gr_children; /* head of line->ln_children */
+ struct list_head gr_groups; /* member of table->tb_groups */
+
+ int state; /* SCOLS_GSTATE_* */
+};
+
+/*
+ * Table line
+ */
+struct libscols_line {
+ int refcount;
+ size_t seqnum;
+
+ void *userdata;
+ char *color; /* default line color */
+
+ struct libscols_cell *cells; /* array with data */
+ size_t ncells; /* number of cells */
+
+ struct list_head ln_lines; /* member of table->tb_lines */
+ struct list_head ln_branch; /* head of line->ln_children */
+ struct list_head ln_children; /* member of line->ln_children or group->gr_children */
+ struct list_head ln_groups; /* member of group->gr_groups */
+
+ struct libscols_line *parent;
+ struct libscols_group *parent_group; /* for group childs */
+ struct libscols_group *group; /* for group members */
+};
+
+enum {
+ SCOLS_FMT_HUMAN = 0, /* default, human readable */
+ SCOLS_FMT_RAW, /* space separated */
+ SCOLS_FMT_EXPORT, /* COLNAME="data" ... */
+ SCOLS_FMT_JSON /* http://en.wikipedia.org/wiki/JSON */
+};
+
+/*
+ * The table
+ */
+struct libscols_table {
+ int refcount;
+ char *name; /* optional table name (for JSON) */
+ size_t ncols; /* number of columns */
+ size_t ntreecols; /* number of columns with SCOLS_FL_TREE */
+ size_t nlines; /* number of lines */
+ size_t termwidth; /* terminal width (number of columns) */
+ size_t termheight; /* terminal height (number of lines) */
+ size_t termreduce; /* extra blank space */
+ int termforce; /* SCOLS_TERMFORCE_* */
+ FILE *out; /* output stream */
+
+ char *colsep; /* column separator */
+ char *linesep; /* line separator */
+
+ struct list_head tb_columns;
+ struct list_head tb_lines;
+
+ struct list_head tb_groups; /* all defined groups */
+ struct libscols_group **grpset;
+ size_t grpset_size;
+
+ size_t ngrpchlds_pending; /* groups with not yet printed children */
+ struct libscols_line *walk_last_tree_root; /* last root, used by scols_walk_() */
+
+ struct libscols_symbols *symbols;
+ struct libscols_cell title; /* optional table title (for humans) */
+
+ int indent; /* indentation counter */
+ int indent_last_sep;/* last printed has been line separator */
+ int format; /* SCOLS_FMT_* */
+
+ size_t termlines_used; /* printed line counter */
+ size_t header_next; /* where repeat header */
+
+ /* flags */
+ unsigned int ascii :1, /* don't use unicode */
+ colors_wanted :1, /* enable colors */
+ is_term :1, /* isatty() */
+ padding_debug :1, /* output visible padding chars */
+ is_dummy_print :1, /* printing used for width calculation only */
+ maxout :1, /* maximize output */
+ minout :1, /* minimize output (mutually exclusive to maxout) */
+ header_repeat :1, /* print header after libscols_table->termheight */
+ header_printed :1, /* header already printed */
+ priv_symbols :1, /* default private symbols */
+ walk_last_done :1, /* last tree root walked */
+ no_headings :1, /* don't print header */
+ no_encode :1, /* don't care about control and non-printable chars */
+ no_linesep :1, /* don't print line separator */
+ no_wrap :1; /* never wrap lines */
+};
+
+#define IS_ITER_FORWARD(_i) ((_i)->direction == SCOLS_ITER_FORWARD)
+#define IS_ITER_BACKWARD(_i) ((_i)->direction == SCOLS_ITER_BACKWARD)
+
+#define SCOLS_ITER_INIT(itr, list) \
+ do { \
+ (itr)->p = IS_ITER_FORWARD(itr) ? \
+ (list)->next : (list)->prev; \
+ (itr)->head = (list); \
+ } while(0)
+
+#define SCOLS_ITER_ITERATE(itr, res, restype, member) \
+ do { \
+ res = list_entry((itr)->p, restype, member); \
+ (itr)->p = IS_ITER_FORWARD(itr) ? \
+ (itr)->p->next : (itr)->p->prev; \
+ } while(0)
+
+
+static inline int scols_iter_is_last(const struct libscols_iter *itr)
+{
+ if (!itr || !itr->head || !itr->p)
+ return 0;
+
+ return itr->p == itr->head;
+}
+
+/*
+ * line.c
+ */
+int scols_line_next_group_child(struct libscols_line *ln,
+ struct libscols_iter *itr,
+ struct libscols_line **chld);
+
+
+/*
+ * table.c
+ */
+int scols_table_next_group(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_group **gr);
+
+/*
+ * buffer.c
+ */
+struct libscols_buffer;
+extern struct libscols_buffer *new_buffer(size_t sz);
+extern void free_buffer(struct libscols_buffer *buf);
+extern int buffer_reset_data(struct libscols_buffer *buf);
+extern int buffer_append_data(struct libscols_buffer *buf, const char *str);
+extern int buffer_append_ntimes(struct libscols_buffer *buf, size_t n, const char *str);
+extern int buffer_set_data(struct libscols_buffer *buf, const char *str);
+extern void buffer_set_art_index(struct libscols_buffer *buf);
+extern char *buffer_get_data(struct libscols_buffer *buf);
+extern size_t buffer_get_size(struct libscols_buffer *buf);
+extern char *buffer_get_safe_data(struct libscols_table *tb,
+ struct libscols_buffer *buf,
+ size_t *cells,
+ const char *safechars);
+extern size_t buffer_get_safe_art_size(struct libscols_buffer *buf);
+
+/*
+ * grouping.c
+ */
+void scols_ref_group(struct libscols_group *gr);
+void scols_group_remove_children(struct libscols_group *gr);
+void scols_group_remove_members(struct libscols_group *gr);
+void scols_unref_group(struct libscols_group *gr);
+void scols_groups_fix_members_order(struct libscols_table *tb);
+int scols_groups_update_grpset(struct libscols_table *tb, struct libscols_line *ln);
+void scols_groups_reset_state(struct libscols_table *tb);
+struct libscols_group *scols_grpset_get_printable_children(struct libscols_table *tb);
+
+/*
+ * walk.c
+ */
+extern int scols_walk_tree(struct libscols_table *tb,
+ struct libscols_column *cl,
+ int (*callback)(struct libscols_table *,
+ struct libscols_line *,
+ struct libscols_column *,
+ void *),
+ void *data);
+extern int scols_walk_is_last(struct libscols_table *tb, struct libscols_line *ln);
+
+/*
+ * calculate.c
+ */
+extern int __scols_calculate(struct libscols_table *tb, struct libscols_buffer *buf);
+
+/*
+ * print.c
+ */
+extern int __cell_to_buffer(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ struct libscols_buffer *buf);
+
+void __scols_cleanup_printing(struct libscols_table *tb, struct libscols_buffer *buf);
+int __scols_initialize_printing(struct libscols_table *tb, struct libscols_buffer **buf);
+int __scols_print_tree(struct libscols_table *tb, struct libscols_buffer *buf);
+int __scols_print_table(struct libscols_table *tb, struct libscols_buffer *buf);
+int __scols_print_header(struct libscols_table *tb, struct libscols_buffer *buf);
+int __scols_print_title(struct libscols_table *tb);
+int __scols_print_range(struct libscols_table *tb,
+ struct libscols_buffer *buf,
+ struct libscols_iter *itr,
+ struct libscols_line *end);
+
+/*
+ * fput.c
+ */
+extern void fput_indent(struct libscols_table *tb);
+extern void fput_table_open(struct libscols_table *tb);
+extern void fput_table_close(struct libscols_table *tb);
+extern void fput_children_open(struct libscols_table *tb);
+extern void fput_children_close(struct libscols_table *tb);
+extern void fput_line_open(struct libscols_table *tb);
+extern void fput_line_close(struct libscols_table *tb, int last, int last_in_table);
+
+static inline int is_tree_root(struct libscols_line *ln)
+{
+ return ln && !ln->parent && !ln->parent_group;
+}
+
+static inline int is_last_tree_root(struct libscols_table *tb, struct libscols_line *ln)
+{
+ if (!ln || !tb || tb->walk_last_tree_root != ln)
+ return 0;
+
+ return 1;
+}
+
+static inline int is_child(struct libscols_line *ln)
+{
+ return ln && ln->parent;
+}
+
+static inline int is_last_child(struct libscols_line *ln)
+{
+ if (!ln || !ln->parent)
+ return 0;
+
+ return list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch);
+}
+
+static inline int is_first_child(struct libscols_line *ln)
+{
+ if (!ln || !ln->parent)
+ return 0;
+
+ return list_entry_is_first(&ln->ln_children, &ln->parent->ln_branch);
+}
+
+
+static inline int is_last_column(struct libscols_column *cl)
+{
+ struct libscols_column *next;
+
+ if (list_entry_is_last(&cl->cl_columns, &cl->table->tb_columns))
+ return 1;
+
+ next = list_entry(cl->cl_columns.next, struct libscols_column, cl_columns);
+ if (next && scols_column_is_hidden(next) && is_last_column(next))
+ return 1;
+ return 0;
+}
+
+static inline int is_last_group_member(struct libscols_line *ln)
+{
+ if (!ln || !ln->group)
+ return 0;
+
+ return list_entry_is_last(&ln->ln_groups, &ln->group->gr_members);
+}
+
+static inline int is_first_group_member(struct libscols_line *ln)
+{
+ if (!ln || !ln->group)
+ return 0;
+
+ return list_entry_is_first(&ln->ln_groups, &ln->group->gr_members);
+}
+
+static inline int is_group_member(struct libscols_line *ln)
+{
+ return ln && ln->group;
+}
+
+static inline int is_last_group_child(struct libscols_line *ln)
+{
+ if (!ln || !ln->parent_group)
+ return 0;
+
+ return list_entry_is_last(&ln->ln_children, &ln->parent_group->gr_children);
+}
+
+static inline int is_group_child(struct libscols_line *ln)
+{
+ return ln && ln->parent_group;
+}
+
+static inline int has_groups(struct libscols_table *tb)
+{
+ return tb && !list_empty(&tb->tb_groups);
+}
+
+static inline int has_children(struct libscols_line *ln)
+{
+ return ln && !list_empty(&ln->ln_branch);
+}
+
+static inline int has_group_children(struct libscols_line *ln)
+{
+ return ln && ln->group && !list_empty(&ln->group->gr_children);
+}
+
+#endif /* _LIBSMARTCOLS_PRIVATE_H */
diff --git a/src/utils/libsmartcols/src/symbols.c b/src/utils/libsmartcols/src/symbols.c
new file mode 100644
index 0000000..2fadfc7
--- /dev/null
+++ b/src/utils/libsmartcols/src/symbols.c
@@ -0,0 +1,293 @@
+/*
+ * symbols.c - routines for symbol handling
+ *
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: symbols
+ * @title: Symbols
+ * @short_description: can be used to overwrite default output chars (for ascii art)
+ *
+ * An API to access and modify data and information per symbol/symbol group.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "smartcolsP.h"
+
+/**
+ * scols_new_symbols:
+ *
+ * Returns: a pointer to a newly allocated struct libscols_symbols instance.
+ */
+struct libscols_symbols *scols_new_symbols(void)
+{
+ struct libscols_symbols *sy = calloc(1, sizeof(struct libscols_symbols));
+
+ if (!sy)
+ return NULL;
+ sy->refcount = 1;
+ return sy;
+}
+
+/**
+ * scols_ref_symbols:
+ * @sy: a pointer to a struct libscols_symbols instance
+ *
+ * Increases the refcount of @sy.
+ */
+void scols_ref_symbols(struct libscols_symbols *sy)
+{
+ if (sy)
+ sy->refcount++;
+}
+
+/**
+ * scols_unref_symbols:
+ * @sy: a pointer to a struct libscols_symbols instance
+ *
+ * Decreases the refcount of @sy.
+ */
+void scols_unref_symbols(struct libscols_symbols *sy)
+{
+ if (sy && --sy->refcount <= 0) {
+ free(sy->tree_branch);
+ free(sy->tree_vert);
+ free(sy->tree_right);
+ free(sy->group_last_member);
+ free(sy->group_middle_member);
+ free(sy->group_first_member);
+ free(sy->group_vert);
+ free(sy->group_horz);
+ free(sy->group_last_child);
+ free(sy->group_middle_child);
+ free(sy->title_padding);
+ free(sy->cell_padding);
+ free(sy);
+ }
+}
+
+/**
+ * scols_symbols_set_branch:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the branch part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_branch(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, tree_branch, str);
+}
+
+/**
+ * scols_symbols_set_vertical:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the vertical part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_vertical(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, tree_vert, str);
+}
+
+/**
+ * scols_symbols_set_right:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the right part of a tree output
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_symbols_set_right(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, tree_right, str);
+}
+
+/**
+ * scols_symbols_set_title_padding:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the symbols which fill title output
+ *
+ * The current implementation uses only the first byte from the padding string.
+ * A multibyte chars are not supported yet.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.28
+ */
+int scols_symbols_set_title_padding(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, title_padding, str);
+}
+
+/**
+ * scols_symbols_set_cell_padding:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the symbols which fill cells
+ *
+ * The padding char has to take up just one cell on the terminal.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_symbols_set_cell_padding(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, cell_padding, str);
+}
+
+
+/**
+ * scols_symbols_set_group_vertical:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the vertival line
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_vertical(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_vert, str);
+}
+
+/**
+ * scols_symbols_set_group_horizontal:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent the horizontal line
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_horizontal(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_horz, str);
+}
+
+/**
+ * scols_symbols_set_group_first_member:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent first member
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_first_member(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_first_member, str);
+}
+
+/**
+ * scols_symbols_set_group_last_member:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent last member
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_last_member(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_last_member, str);
+}
+
+/**
+ * scols_symbols_set_group_middle:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent middle member
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_middle_member(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_middle_member, str);
+}
+
+/**
+ * scols_symbols_set_group_last_child:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent last child
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_last_child(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_last_child, str);
+}
+
+/**
+ * scols_symbols_set_group_middle_child:
+ * @sy: a pointer to a struct libscols_symbols instance
+ * @str: a string which will represent last child
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.34
+ */
+int scols_symbols_set_group_middle_child(struct libscols_symbols *sy, const char *str)
+{
+ return strdup_to_struct_member(sy, group_middle_child, str);
+}
+
+/**
+ * scols_copy_symbols:
+ * @sy: a pointer to a struct libscols_symbols instance
+ *
+ * Returns: a newly allocated copy of the @sy symbol group or NULL in case of an error.
+ */
+struct libscols_symbols *scols_copy_symbols(const struct libscols_symbols *sy)
+{
+ struct libscols_symbols *ret;
+ int rc;
+
+ assert(sy);
+ if (!sy)
+ return NULL;
+
+ ret = scols_new_symbols();
+ if (!ret)
+ return NULL;
+
+ rc = scols_symbols_set_branch(ret, sy->tree_branch);
+ if (!rc)
+ rc = scols_symbols_set_vertical(ret, sy->tree_vert);
+ if (!rc)
+ rc = scols_symbols_set_right(ret, sy->tree_right);
+ if (!rc)
+ rc = scols_symbols_set_group_vertical(ret, sy->group_vert);
+ if (!rc)
+ rc = scols_symbols_set_group_horizontal(ret, sy->group_horz);
+ if (!rc)
+ rc = scols_symbols_set_group_first_member(ret, sy->group_first_member);
+ if (!rc)
+ rc = scols_symbols_set_group_last_member(ret, sy->group_last_member);
+ if (!rc)
+ rc = scols_symbols_set_group_middle_member(ret, sy->group_middle_member);
+ if (!rc)
+ rc = scols_symbols_set_group_middle_child(ret, sy->group_middle_child);
+ if (!rc)
+ rc = scols_symbols_set_group_last_child(ret, sy->group_last_child);
+ if (!rc)
+ rc = scols_symbols_set_title_padding(ret, sy->title_padding);
+ if (!rc)
+ rc = scols_symbols_set_cell_padding(ret, sy->cell_padding);
+ if (!rc)
+ return ret;
+
+ scols_unref_symbols(ret);
+ return NULL;
+}
diff --git a/src/utils/libsmartcols/src/table.c b/src/utils/libsmartcols/src/table.c
new file mode 100644
index 0000000..a3ba21d
--- /dev/null
+++ b/src/utils/libsmartcols/src/table.c
@@ -0,0 +1,1691 @@
+/*
+ * table.c - functions handling the data at the table level
+ *
+ * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com>
+ * Copyright (C) 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: table
+ * @title: Table
+ * @short_description: container for rows and columns
+ *
+ * Table data manipulation API.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+
+#include "nls.h"
+#include "ttyutils.h"
+#include "smartcolsP.h"
+
+#ifdef HAVE_WIDECHAR
+#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char | */
+#define UTF_VR "\342\224\234" /* U+251C, Vertical and right |- */
+#define UTF_H "\342\224\200" /* U+2500, Horizontal - */
+#define UTF_UR "\342\224\224" /* U+2514, Up and right '- */
+
+#define UTF_V3 "\342\224\206" /* U+2506 Triple Dash Vertical | */
+#define UTF_H3 "\342\224\210" /* U+2504 Triple Dash Horizontal - */
+#define UTF_DR "\342\224\214" /* U+250C Down and Right ,- */
+#define UTF_DH "\342\224\254" /* U+252C Down and Horizontal |' */
+
+#define UTF_TR "\342\226\266" /* U+25B6 Black Right-Pointing Triangle > */
+#endif /* !HAVE_WIDECHAR */
+
+#define is_last_column(_tb, _cl) \
+ list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns)
+
+
+static void check_padding_debug(struct libscols_table *tb)
+{
+ const char *str;
+
+ assert(libsmartcols_debug_mask); /* debug has to be enabled! */
+
+ str = getenv("LIBSMARTCOLS_DEBUG_PADDING");
+ if (!str || (strcmp(str, "on") != 0 && strcmp(str, "1") != 0))
+ return;
+
+ DBG(INIT, ul_debugobj(tb, "padding debug: ENABLE"));
+ tb->padding_debug = 1;
+}
+
+/**
+ * scols_new_table:
+ *
+ * Returns: A newly allocated table.
+ */
+struct libscols_table *scols_new_table(void)
+{
+ struct libscols_table *tb;
+ int c, l;
+
+ tb = calloc(1, sizeof(struct libscols_table));
+ if (!tb)
+ return NULL;
+
+ tb->refcount = 1;
+ tb->out = stdout;
+
+ get_terminal_dimension(&c, &l);
+ tb->termwidth = c > 0 ? c : 80;
+ tb->termheight = l > 0 ? l : 24;
+
+ INIT_LIST_HEAD(&tb->tb_lines);
+ INIT_LIST_HEAD(&tb->tb_columns);
+ INIT_LIST_HEAD(&tb->tb_groups);
+
+ DBG(TAB, ul_debugobj(tb, "alloc"));
+ ON_DBG(INIT, check_padding_debug(tb));
+
+ return tb;
+}
+
+/**
+ * scols_ref_table:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Increases the refcount of @tb.
+ */
+void scols_ref_table(struct libscols_table *tb)
+{
+ if (tb)
+ tb->refcount++;
+}
+
+static void scols_table_remove_groups(struct libscols_table *tb)
+{
+ while (!list_empty(&tb->tb_groups)) {
+ struct libscols_group *gr = list_entry(tb->tb_groups.next,
+ struct libscols_group, gr_groups);
+ scols_group_remove_children(gr);
+ scols_group_remove_members(gr);
+ scols_unref_group(gr);
+ }
+}
+
+/**
+ * scols_unref_table:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Decreases the refcount of @tb. When the count falls to zero, the instance
+ * is automatically deallocated.
+ */
+void scols_unref_table(struct libscols_table *tb)
+{
+ if (tb && (--tb->refcount <= 0)) {
+ DBG(TAB, ul_debugobj(tb, "dealloc <-"));
+ scols_table_remove_groups(tb);
+ scols_table_remove_lines(tb);
+ scols_table_remove_columns(tb);
+ scols_unref_symbols(tb->symbols);
+ scols_reset_cell(&tb->title);
+ free(tb->grpset);
+ free(tb->linesep);
+ free(tb->colsep);
+ free(tb->name);
+ free(tb);
+ DBG(TAB, ul_debug("<- done"));
+ }
+}
+
+/* Private API */
+int scols_table_next_group(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_group **gr)
+{
+ int rc = 1;
+
+ if (!tb || !itr || !gr)
+ return -EINVAL;
+ *gr = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &tb->tb_groups);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *gr, struct libscols_group, gr_groups);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_table_set_name:
+ * @tb: a pointer to a struct libscols_table instance
+ * @name: a name
+ *
+ * The table name is used for example for JSON top level object name.
+ *
+ * Returns: 0, a negative number in case of an error.
+ *
+ * Since: 2.27
+ */
+int scols_table_set_name(struct libscols_table *tb, const char *name)
+{
+ return strdup_to_struct_member(tb, name, name);
+}
+
+/**
+ * scols_table_get_name:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Returns: The current name setting of the table @tb
+ *
+ * Since: 2.29
+ */
+const char *scols_table_get_name(const struct libscols_table *tb)
+{
+ return tb->name;
+}
+
+/**
+ * scols_table_get_title:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * The returned pointer is possible to modify by cell functions. Note that
+ * title output alignment on non-tty is hardcoded to 80 output chars. For the
+ * regular terminal it's based on terminal width.
+ *
+ * Returns: Title of the table, or NULL in case of blank title.
+ *
+ * Since: 2.28
+ */
+struct libscols_cell *scols_table_get_title(struct libscols_table *tb)
+{
+ return &tb->title;
+}
+
+/**
+ * scols_table_add_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Adds @cl to @tb's column list. The column cannot be shared between more
+ * tables.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_add_column(struct libscols_table *tb, struct libscols_column *cl)
+{
+ struct libscols_iter itr;
+ struct libscols_line *ln;
+ int rc = 0;
+
+ if (!tb || !cl || cl->table)
+ return -EINVAL;
+
+ if (!list_empty(&cl->cl_columns))
+ return -EINVAL;
+
+ if (cl->flags & SCOLS_FL_TREE)
+ tb->ntreecols++;
+
+ DBG(TAB, ul_debugobj(tb, "add column"));
+ list_add_tail(&cl->cl_columns, &tb->tb_columns);
+ cl->seqnum = tb->ncols++;
+ cl->table = tb;
+ scols_ref_column(cl);
+
+ if (list_empty(&tb->tb_lines))
+ return 0;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+
+ /* Realloc line cell arrays
+ */
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ rc = scols_line_alloc_cells(ln, tb->ncols);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_table_remove_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @cl: a pointer to a struct libscols_column instance
+ *
+ * Removes @cl from @tb.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_remove_column(struct libscols_table *tb,
+ struct libscols_column *cl)
+{
+ if (!tb || !cl || !list_empty(&tb->tb_lines))
+ return -EINVAL;
+
+ if (cl->flags & SCOLS_FL_TREE)
+ tb->ntreecols--;
+
+ DBG(TAB, ul_debugobj(tb, "remove column"));
+ list_del_init(&cl->cl_columns);
+ tb->ncols--;
+ cl->table = NULL;
+ scols_unref_column(cl);
+ return 0;
+}
+
+/**
+ * scols_table_remove_columns:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Removes all of @tb's columns.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_remove_columns(struct libscols_table *tb)
+{
+ if (!tb || !list_empty(&tb->tb_lines))
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "remove all columns"));
+ while (!list_empty(&tb->tb_columns)) {
+ struct libscols_column *cl = list_entry(tb->tb_columns.next,
+ struct libscols_column, cl_columns);
+ scols_table_remove_column(tb, cl);
+ }
+ return 0;
+}
+
+/**
+ * scols_table_move_column:
+ * @tb: table
+ * @pre: column before the column
+ * @cl: column to move
+ *
+ * Move the @cl behind @pre. If the @pre is NULL then the @col is the first
+ * column in the table.
+ *
+ * Since: 2.30
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_move_column(struct libscols_table *tb,
+ struct libscols_column *pre,
+ struct libscols_column *cl)
+{
+ struct list_head *head;
+ struct libscols_iter itr;
+ struct libscols_column *p;
+ struct libscols_line *ln;
+ size_t n = 0, oldseq;
+
+ if (!tb || !cl)
+ return -EINVAL;
+
+ if (pre && pre->seqnum + 1 == cl->seqnum)
+ return 0;
+ if (pre == NULL && cl->seqnum == 0)
+ return 0;
+
+ DBG(TAB, ul_debugobj(tb, "move column %zu behind %zu",
+ cl->seqnum, pre? pre->seqnum : 0));
+
+ list_del_init(&cl->cl_columns); /* remove from old position */
+
+ head = pre ? &pre->cl_columns : &tb->tb_columns;
+ list_add(&cl->cl_columns, head); /* add to the new place */
+
+ oldseq = cl->seqnum;
+
+ /* fix seq. numbers */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &p) == 0)
+ p->seqnum = n++;
+
+ /* move data in lines */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0)
+ scols_line_move_cells(ln, cl->seqnum, oldseq);
+ return 0;
+}
+
+/**
+ * scols_table_new_column:
+ * @tb: table
+ * @name: column header
+ * @whint: column width hint (absolute width: N > 1; relative width: 0 < N < 1)
+ * @flags: flags integer
+ *
+ * This is shortcut for
+ *
+ * cl = scols_new_column();
+ * scols_column_set_....(cl, ...);
+ * scols_table_add_column(tb, cl);
+ *
+ * The column width is possible to define by:
+ *
+ * @whint: 0 < N < 1 : relative width, percent of terminal width
+ *
+ * @whint: N >= 1 : absolute width, empty column will be truncated to
+ * the column header width if no specified STRICTWIDTH flag
+ *
+ * Note that if table has disabled "maxout" flag (disabled by default) than
+ * relative width is used as a hint only. It's possible that column will be
+ * narrow if the specified size is too large for column data.
+ *
+ *
+ * If the width of all columns is greater than terminal width then library
+ * tries to reduce width of the individual columns. It's done in three stages:
+ *
+ * #1 reduce columns with SCOLS_FL_TRUNC flag and with relative width if the
+ * width is greater than width defined by @whint (@whint * terminal_width)
+ *
+ * #2 reduce all columns with SCOLS_FL_TRUNC flag
+ *
+ * #3 reduce all columns with relative width
+ *
+ * The next stage is always used if the previous stage is unsuccessful. Note
+ * that SCOLS_FL_WRAP is interpreted as SCOLS_FL_TRUNC when calculate column
+ * width (if custom wrap function is not specified), but the final text is not
+ * truncated, but wrapped to multi-line cell.
+ *
+ *
+ * The column is necessary to address by sequential number. The first defined
+ * column has the colnum = 0. For example:
+ *
+ * scols_table_new_column(tab, "FOO", 0.5, 0); // colnum = 0
+ * scols_table_new_column(tab, "BAR", 0.5, 0); // colnum = 1
+ * .
+ * .
+ * scols_line_get_cell(line, 0); // FOO column
+ * scols_line_get_cell(line, 1); // BAR column
+ *
+ * Returns: newly allocated column
+ */
+struct libscols_column *scols_table_new_column(struct libscols_table *tb,
+ const char *name,
+ double whint,
+ int flags)
+{
+ struct libscols_column *cl;
+ struct libscols_cell *hr;
+
+ if (!tb)
+ return NULL;
+
+ DBG(TAB, ul_debugobj(tb, "new column name=%s, whint=%g, flags=%d",
+ name, whint, flags));
+ cl = scols_new_column();
+ if (!cl)
+ return NULL;
+
+ /* set column name */
+ hr = scols_column_get_header(cl);
+ if (!hr)
+ goto err;
+ if (scols_cell_set_data(hr, name))
+ goto err;
+
+ scols_column_set_whint(cl, whint);
+ scols_column_set_flags(cl, flags);
+
+ if (scols_table_add_column(tb, cl)) /* this increments column ref-counter */
+ goto err;
+
+ scols_unref_column(cl);
+ return cl;
+err:
+ scols_unref_column(cl);
+ return NULL;
+}
+
+/**
+ * scols_table_next_column:
+ * @tb: a pointer to a struct libscols_table instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @cl: a pointer to a pointer to a struct libscols_column instance
+ *
+ * Returns the next column of @tb via @cl.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_next_column(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_column **cl)
+{
+ int rc = 1;
+
+ if (!tb || !itr || !cl)
+ return -EINVAL;
+ *cl = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &tb->tb_columns);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *cl, struct libscols_column, cl_columns);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_table_set_columns_iter:
+ * @tb: tab pointer
+ * @itr: iterator
+ * @cl: tab entry
+ *
+ * Sets @iter to the position of @cl in the file @tb.
+ *
+ * Returns: 0 on success, negative number in case of error.
+ *
+ * Since: 2.35
+ */
+int scols_table_set_columns_iter(
+ struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_column *cl)
+{
+ if (!tb || !itr || !cl)
+ return -EINVAL;
+
+ if (cl->table != tb)
+ return -EINVAL;
+
+ SCOLS_ITER_INIT(itr, &tb->tb_columns);
+ itr->p = &cl->cl_columns;
+
+ return 0;
+}
+
+/**
+ * scols_table_get_ncols:
+ * @tb: table
+ *
+ * Returns: the ncols table member.
+ */
+size_t scols_table_get_ncols(const struct libscols_table *tb)
+{
+ return tb->ncols;
+}
+
+/**
+ * scols_table_get_nlines:
+ * @tb: table
+ *
+ * Returns: the nlines table member.
+ */
+size_t scols_table_get_nlines(const struct libscols_table *tb)
+{
+ return tb->nlines;
+}
+
+/**
+ * scols_table_set_stream:
+ * @tb: table
+ * @stream: output stream
+ *
+ * Sets the output stream for table @tb.
+ *
+ * Returns: 0, a negative number in case of an error.
+ */
+int scols_table_set_stream(struct libscols_table *tb, FILE *stream)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "setting alternative stream"));
+ tb->out = stream;
+ return 0;
+}
+
+/**
+ * scols_table_get_stream:
+ * @tb: table
+ *
+ * Gets the output stream for table @tb.
+ *
+ * Returns: stream pointer, NULL in case of an error or an unset stream.
+ */
+FILE *scols_table_get_stream(const struct libscols_table *tb)
+{
+ return tb->out;
+}
+
+/**
+ * scols_table_reduce_termwidth:
+ * @tb: table
+ * @reduce: width
+ *
+ * If necessary then libsmartcols use all terminal width, the @reduce setting
+ * provides extra space (for example for borders in ncurses applications).
+ *
+ * The @reduce must be smaller than terminal width, otherwise it's silently
+ * ignored. The reduction is not applied when STDOUT_FILENO is not terminal.
+ *
+ * Note that after output initialization (scols_table_print_* calls) the width
+ * will be reduced, this behavior affects subsequenced scols_table_get_termwidth()
+ * calls.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_reduce_termwidth(struct libscols_table *tb, size_t reduce)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "reduce terminal width: %zu", reduce));
+ tb->termreduce = reduce;
+ return 0;
+}
+
+/**
+ * scols_table_get_column:
+ * @tb: table
+ * @n: number of column (0..N)
+ *
+ * Returns: pointer to column or NULL
+ */
+struct libscols_column *scols_table_get_column(struct libscols_table *tb,
+ size_t n)
+{
+ struct libscols_iter itr;
+ struct libscols_column *cl;
+
+ if (!tb)
+ return NULL;
+ if (n >= tb->ncols)
+ return NULL;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ if (cl->seqnum == n)
+ return cl;
+ }
+ return NULL;
+}
+
+/**
+ * scols_table_add_line:
+ * @tb: table
+ * @ln: line
+ *
+ * Note that this function calls scols_line_alloc_cells() if number
+ * of the cells in the line is too small for @tb.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_add_line(struct libscols_table *tb, struct libscols_line *ln)
+{
+ if (!tb || !ln)
+ return -EINVAL;
+
+ if (!list_empty(&ln->ln_lines))
+ return -EINVAL;
+
+ if (tb->ncols > ln->ncells) {
+ int rc = scols_line_alloc_cells(ln, tb->ncols);
+ if (rc)
+ return rc;
+ }
+
+ DBG(TAB, ul_debugobj(tb, "add line"));
+ list_add_tail(&ln->ln_lines, &tb->tb_lines);
+ ln->seqnum = tb->nlines++;
+ scols_ref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_table_remove_line:
+ * @tb: table
+ * @ln: line
+ *
+ * Note that this function does not destroy the parent<->child relationship between lines.
+ * You have to call scols_line_remove_child()
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_remove_line(struct libscols_table *tb,
+ struct libscols_line *ln)
+{
+ if (!tb || !ln)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "remove line"));
+ list_del_init(&ln->ln_lines);
+ tb->nlines--;
+ scols_unref_line(ln);
+ return 0;
+}
+
+/**
+ * scols_table_remove_lines:
+ * @tb: table
+ *
+ * This empties the table and also destroys all the parent<->child relationships.
+ */
+void scols_table_remove_lines(struct libscols_table *tb)
+{
+ if (!tb)
+ return;
+
+ DBG(TAB, ul_debugobj(tb, "remove all lines"));
+ while (!list_empty(&tb->tb_lines)) {
+ struct libscols_line *ln = list_entry(tb->tb_lines.next,
+ struct libscols_line, ln_lines);
+ if (ln->parent)
+ scols_line_remove_child(ln->parent, ln);
+ scols_table_remove_line(tb, ln);
+ }
+}
+
+/**
+ * scols_table_next_line:
+ * @tb: a pointer to a struct libscols_table instance
+ * @itr: a pointer to a struct libscols_iter instance
+ * @ln: a pointer to a pointer to a struct libscols_line instance
+ *
+ * Finds the next line and returns a pointer to it via @ln.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_next_line(struct libscols_table *tb,
+ struct libscols_iter *itr,
+ struct libscols_line **ln)
+{
+ int rc = 1;
+
+ if (!tb || !itr || !ln)
+ return -EINVAL;
+ *ln = NULL;
+
+ if (!itr->head)
+ SCOLS_ITER_INIT(itr, &tb->tb_lines);
+ if (itr->p != itr->head) {
+ SCOLS_ITER_ITERATE(itr, *ln, struct libscols_line, ln_lines);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * scols_table_new_line:
+ * @tb: table
+ * @parent: parental line or NULL
+ *
+ * This is shortcut for
+ *
+ * ln = scols_new_line();
+ * scols_table_add_line(tb, ln);
+ * scols_line_add_child(parent, ln);
+ *
+ *
+ * Returns: newly allocate line
+ */
+struct libscols_line *scols_table_new_line(struct libscols_table *tb,
+ struct libscols_line *parent)
+{
+ struct libscols_line *ln;
+
+ if (!tb)
+ return NULL;
+
+ ln = scols_new_line();
+ if (!ln)
+ return NULL;
+
+ if (scols_table_add_line(tb, ln))
+ goto err;
+ if (parent)
+ scols_line_add_child(parent, ln);
+
+ scols_unref_line(ln); /* ref-counter incremented by scols_table_add_line() */
+ return ln;
+err:
+ scols_unref_line(ln);
+ return NULL;
+}
+
+/**
+ * scols_table_get_line:
+ * @tb: table
+ * @n: column number (0..N)
+ *
+ * Returns: a line or NULL
+ */
+struct libscols_line *scols_table_get_line(struct libscols_table *tb,
+ size_t n)
+{
+ struct libscols_iter itr;
+ struct libscols_line *ln;
+
+ if (!tb)
+ return NULL;
+ if (n >= tb->nlines)
+ return NULL;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->seqnum == n)
+ return ln;
+ }
+ return NULL;
+}
+
+/**
+ * scols_copy_table:
+ * @tb: table
+ *
+ * Creates a new independent table copy, except struct libscols_symbols that
+ * are shared between the tables.
+ *
+ * Returns: a newly allocated copy of @tb
+ */
+struct libscols_table *scols_copy_table(struct libscols_table *tb)
+{
+ struct libscols_table *ret;
+ struct libscols_line *ln;
+ struct libscols_column *cl;
+ struct libscols_iter itr;
+
+ if (!tb)
+ return NULL;
+ ret = scols_new_table();
+ if (!ret)
+ return NULL;
+
+ DBG(TAB, ul_debugobj(tb, "copy"));
+
+ if (tb->symbols)
+ scols_table_set_symbols(ret, tb->symbols);
+
+ /* columns */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_column(tb, &itr, &cl) == 0) {
+ cl = scols_copy_column(cl);
+ if (!cl)
+ goto err;
+ if (scols_table_add_column(ret, cl))
+ goto err;
+ scols_unref_column(cl);
+ }
+
+ /* lines */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ struct libscols_line *newln = scols_copy_line(ln);
+ if (!newln)
+ goto err;
+ if (scols_table_add_line(ret, newln))
+ goto err;
+ if (ln->parent) {
+ struct libscols_line *p =
+ scols_table_get_line(ret, ln->parent->seqnum);
+ if (p)
+ scols_line_add_child(p, newln);
+ }
+ scols_unref_line(newln);
+ }
+
+ /* separators */
+ if (scols_table_set_column_separator(ret, tb->colsep) ||
+ scols_table_set_line_separator(ret, tb->linesep))
+ goto err;
+
+ return ret;
+err:
+ scols_unref_table(ret);
+ return NULL;
+}
+
+/**
+ * scols_table_set_default_symbols:
+ * @tb: table
+ *
+ * The library check the current environment to select ASCII or UTF8 symbols.
+ * This default behavior could be controlled by scols_table_enable_ascii().
+ *
+ * Use scols_table_set_symbols() to unset symbols or use your own setting.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_table_set_default_symbols(struct libscols_table *tb)
+{
+ struct libscols_symbols *sy;
+ int rc;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "setting default symbols"));
+
+ sy = scols_new_symbols();
+ if (!sy)
+ return -ENOMEM;
+
+#if defined(HAVE_WIDECHAR)
+ if (!scols_table_is_ascii(tb) &&
+ !strcmp(nl_langinfo(CODESET), "UTF-8")) {
+ /* tree chart */
+ scols_symbols_set_branch(sy, UTF_VR UTF_H);
+ scols_symbols_set_vertical(sy, UTF_V " ");
+ scols_symbols_set_right(sy, UTF_UR UTF_H);
+ /* groups chart */
+ scols_symbols_set_group_horizontal(sy, UTF_H3);
+ scols_symbols_set_group_vertical(sy, UTF_V3);
+
+ scols_symbols_set_group_first_member(sy, UTF_DR UTF_H3 UTF_TR);
+ scols_symbols_set_group_last_member(sy, UTF_UR UTF_DH UTF_TR);
+ scols_symbols_set_group_middle_member(sy, UTF_VR UTF_H3 UTF_TR);
+ scols_symbols_set_group_last_child(sy, UTF_UR UTF_H3);
+ scols_symbols_set_group_middle_child(sy, UTF_VR UTF_H3);
+ } else
+#endif
+ {
+ /* tree chart */
+ scols_symbols_set_branch(sy, "|-");
+ scols_symbols_set_vertical(sy, "| ");
+ scols_symbols_set_right(sy, "`-");
+ /* groups chart */
+ scols_symbols_set_group_horizontal(sy, "-");
+ scols_symbols_set_group_vertical(sy, "|");
+
+ scols_symbols_set_group_first_member(sy, ",->");
+ scols_symbols_set_group_last_member(sy, "'->");
+ scols_symbols_set_group_middle_member(sy, "|->");
+ scols_symbols_set_group_last_child(sy, "`-");
+ scols_symbols_set_group_middle_child(sy, "|-");
+ }
+ scols_symbols_set_title_padding(sy, " ");
+ scols_symbols_set_cell_padding(sy, " ");
+
+ rc = scols_table_set_symbols(tb, sy);
+ scols_unref_symbols(sy);
+ return rc;
+}
+
+
+/**
+ * scols_table_set_symbols:
+ * @tb: table
+ * @sy: symbols or NULL
+ *
+ * Add a reference to @sy from the table. The symbols are used by library to
+ * draw tree output. If no symbols are used for the table then library creates
+ * default temporary symbols to draw output by scols_table_set_default_symbols().
+ *
+ * If @sy is NULL then remove reference from the currently used symbols.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_symbols(struct libscols_table *tb,
+ struct libscols_symbols *sy)
+{
+ if (!tb)
+ return -EINVAL;
+
+ /* remove old */
+ if (tb->symbols) {
+ DBG(TAB, ul_debugobj(tb, "remove symbols reference"));
+ scols_unref_symbols(tb->symbols);
+ tb->symbols = NULL;
+ }
+
+ /* set new */
+ if (sy) { /* ref user defined */
+ DBG(TAB, ul_debugobj(tb, "set symbols"));
+ tb->symbols = sy;
+ scols_ref_symbols(sy);
+ }
+ return 0;
+}
+
+/**
+ * scols_table_get_symbols:
+ * @tb: table
+ *
+ * Returns: pointer to symbols table.
+ *
+ * Since: 2.29
+ */
+struct libscols_symbols *scols_table_get_symbols(const struct libscols_table *tb)
+{
+ return tb->symbols;
+}
+
+/**
+ * scols_table_enable_nolinesep:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable line separator printing. This is useful if you want to
+ * re-printing the same line more than once (e.g. progress bar). Don't use it
+ * if you're not sure.
+ *
+ * Note that for the last line in the table the separator is disabled at all.
+ * The library differentiate between table terminator and line terminator
+ * (although for standard output \n byte is used in both cases).
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_nolinesep(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "nolinesep: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->no_linesep = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_is_nolinesep:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Returns: 1 if line separator printing is disabled.
+ *
+ * Since: 2.29
+ */
+int scols_table_is_nolinesep(const struct libscols_table *tb)
+{
+ return tb->no_linesep;
+}
+
+/**
+ * scols_table_enable_colors:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable colors.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_colors(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "colors: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->colors_wanted = enable;
+ return 0;
+}
+
+/**
+ * scols_table_enable_raw:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable raw output format. The parsable output formats
+ * (export, raw, JSON, ...) are mutually exclusive.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_raw(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "raw: %s", enable ? "ENABLE" : "DISABLE"));
+ if (enable)
+ tb->format = SCOLS_FMT_RAW;
+ else if (tb->format == SCOLS_FMT_RAW)
+ tb->format = 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_json:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable JSON output format. The parsable output formats
+ * (export, raw, JSON, ...) are mutually exclusive.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ *
+ * Since: 2.27
+ */
+int scols_table_enable_json(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "json: %s", enable ? "ENABLE" : "DISABLE"));
+ if (enable)
+ tb->format = SCOLS_FMT_JSON;
+ else if (tb->format == SCOLS_FMT_JSON)
+ tb->format = 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_export:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable export output format (COLUMNAME="value" ...).
+ * The parsable output formats (export and raw) are mutually exclusive.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_export(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "export: %s", enable ? "ENABLE" : "DISABLE"));
+ if (enable)
+ tb->format = SCOLS_FMT_EXPORT;
+ else if (tb->format == SCOLS_FMT_EXPORT)
+ tb->format = 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_ascii:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * The ASCII-only output is relevant for tree-like outputs. The library
+ * checks if the current environment is UTF8 compatible by default. This
+ * function overrides this check and force the library to use ASCII chars
+ * for the tree.
+ *
+ * If a custom libcols_symbols are specified (see scols_table_set_symbols()
+ * then ASCII flag setting is ignored.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_ascii(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "ascii: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->ascii = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_noheadings:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable header line.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_noheadings(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "noheading: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->no_headings = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_header_repeat:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Enable/disable header line repeat. The header line is printed only once by
+ * default. Note that the flag will be silently ignored and disabled if the
+ * output is not on terminal or output format is JSON, raw, etc.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ *
+ * Since: 2.31
+ */
+int scols_table_enable_header_repeat(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "header-repeat: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->header_repeat = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_maxout:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * The extra space after last column is ignored by default. The output
+ * maximization add padding for all columns.
+ *
+ * This setting is mutually exclusive to scols_table_enable_minout().
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ */
+int scols_table_enable_maxout(struct libscols_table *tb, int enable)
+{
+ if (!tb || tb->minout)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "maxout: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->maxout = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_minout:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Force library to terminate line after last column with data. The extra
+ * padding is not added to the empty cells at the end of the line. The default is fill
+ * tailing empty cells except the last line cell.
+ *
+ * This setting is mutually exclusive to scols_table_enable_maxout().
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ *
+ * Since: 2.35
+ */
+int scols_table_enable_minout(struct libscols_table *tb, int enable)
+{
+ if (!tb || tb->maxout)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "minout: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->minout = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_enable_nowrap:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * Never continue on next line, remove last column(s) when too large, truncate last column.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ *
+ * Since: 2.28
+ */
+int scols_table_enable_nowrap(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "nowrap: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->no_wrap = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_is_nowrap:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Returns: 1 if nowrap is enabled.
+ *
+ * Since: 2.29
+ */
+int scols_table_is_nowrap(const struct libscols_table *tb)
+{
+ return tb->no_wrap;
+}
+
+/**
+ * scols_table_enable_noencoding:
+ * @tb: table
+ * @enable: 1 or 0
+ *
+ * The library encode non-printable and control chars by \xHEX by default.
+ *
+ * Returns: 0 on success, negative number in case of an error.
+ *
+ * Since: 2.31
+ */
+int scols_table_enable_noencoding(struct libscols_table *tb, int enable)
+{
+ if (!tb)
+ return -EINVAL;
+ DBG(TAB, ul_debugobj(tb, "encoding: %s", enable ? "ENABLE" : "DISABLE"));
+ tb->no_encode = enable ? 1 : 0;
+ return 0;
+}
+
+/**
+ * scols_table_is_noencoding:
+ * @tb: a pointer to a struct libscols_table instance
+ *
+ * Returns: 1 if encoding is disabled.
+ *
+ * Since: 2.31
+ */
+int scols_table_is_noencoding(const struct libscols_table *tb)
+{
+ return tb->no_encode;
+}
+
+/**
+ * scols_table_colors_wanted:
+ * @tb: table
+ *
+ * Returns: 1 if colors are enabled.
+ */
+int scols_table_colors_wanted(const struct libscols_table *tb)
+{
+ return tb->colors_wanted;
+}
+
+/**
+ * scols_table_is_empty:
+ * @tb: table
+ *
+ * Returns: 1 if the table is empty.
+ */
+int scols_table_is_empty(const struct libscols_table *tb)
+{
+ return !tb->nlines;
+}
+
+/**
+ * scols_table_is_ascii:
+ * @tb: table
+ *
+ * Returns: 1 if ASCII tree is enabled.
+ */
+int scols_table_is_ascii(const struct libscols_table *tb)
+{
+ return tb->ascii;
+}
+
+/**
+ * scols_table_is_noheadings:
+ * @tb: table
+ *
+ * Returns: 1 if header output is disabled.
+ */
+int scols_table_is_noheadings(const struct libscols_table *tb)
+{
+ return tb->no_headings;
+}
+
+/**
+ * scols_table_is_header_repeat
+ * @tb: table
+ *
+ * Returns: 1 if header repeat is enabled.
+ *
+ * Since: 2.31
+ */
+int scols_table_is_header_repeat(const struct libscols_table *tb)
+{
+ return tb->header_repeat;
+}
+
+/**
+ * scols_table_is_export:
+ * @tb: table
+ *
+ * Returns: 1 if export output format is enabled.
+ */
+int scols_table_is_export(const struct libscols_table *tb)
+{
+ return tb->format == SCOLS_FMT_EXPORT;
+}
+
+/**
+ * scols_table_is_raw:
+ * @tb: table
+ *
+ * Returns: 1 if raw output format is enabled.
+ */
+int scols_table_is_raw(const struct libscols_table *tb)
+{
+ return tb->format == SCOLS_FMT_RAW;
+}
+
+/**
+ * scols_table_is_json:
+ * @tb: table
+ *
+ * Returns: 1 if JSON output format is enabled.
+ *
+ * Since: 2.27
+ */
+int scols_table_is_json(const struct libscols_table *tb)
+{
+ return tb->format == SCOLS_FMT_JSON;
+}
+
+/**
+ * scols_table_is_maxout
+ * @tb: table
+ *
+ * Returns: 1 if output maximization is enabled or 0
+ */
+int scols_table_is_maxout(const struct libscols_table *tb)
+{
+ return tb->maxout;
+}
+
+/**
+ * scols_table_is_minout
+ * @tb: table
+ *
+ * Returns: 1 if output minimization is enabled or 0
+ *
+ * Since: 2.35
+ */
+int scols_table_is_minout(const struct libscols_table *tb)
+{
+ return tb->minout;
+}
+
+/**
+ * scols_table_is_tree:
+ * @tb: table
+ *
+ * Returns: returns 1 tree-like output is expected.
+ */
+int scols_table_is_tree(const struct libscols_table *tb)
+{
+ return tb->ntreecols > 0;
+}
+
+/**
+ * scols_table_set_column_separator:
+ * @tb: table
+ * @sep: separator
+ *
+ * Sets the column separator of @tb to @sep.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_column_separator(struct libscols_table *tb, const char *sep)
+{
+ return strdup_to_struct_member(tb, colsep, sep);
+}
+
+/**
+ * scols_table_set_line_separator:
+ * @tb: table
+ * @sep: separator
+ *
+ * Sets the line separator of @tb to @sep.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_table_set_line_separator(struct libscols_table *tb, const char *sep)
+{
+ return strdup_to_struct_member(tb, linesep, sep);
+}
+
+/**
+ * scols_table_get_column_separator:
+ * @tb: table
+ *
+ * Returns: @tb column separator, NULL in case of an error
+ */
+const char *scols_table_get_column_separator(const struct libscols_table *tb)
+{
+ return tb->colsep;
+}
+
+/**
+ * scols_table_get_line_separator:
+ * @tb: table
+ *
+ * Returns: @tb line separator, NULL in case of an error
+ */
+const char *scols_table_get_line_separator(const struct libscols_table *tb)
+{
+ return tb->linesep;
+}
+/* for lines in the struct libscols_line->ln_lines list */
+static int cells_cmp_wrapper_lines(struct list_head *a, struct list_head *b, void *data)
+{
+ struct libscols_column *cl = (struct libscols_column *) data;
+ struct libscols_line *ra, *rb;
+ struct libscols_cell *ca, *cb;
+
+ assert(a);
+ assert(b);
+ assert(cl);
+
+ ra = list_entry(a, struct libscols_line, ln_lines);
+ rb = list_entry(b, struct libscols_line, ln_lines);
+ ca = scols_line_get_cell(ra, cl->seqnum);
+ cb = scols_line_get_cell(rb, cl->seqnum);
+
+ return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
+}
+
+/* for lines in the struct libscols_line->ln_children list */
+static int cells_cmp_wrapper_children(struct list_head *a, struct list_head *b, void *data)
+{
+ struct libscols_column *cl = (struct libscols_column *) data;
+ struct libscols_line *ra, *rb;
+ struct libscols_cell *ca, *cb;
+
+ assert(a);
+ assert(b);
+ assert(cl);
+
+ ra = list_entry(a, struct libscols_line, ln_children);
+ rb = list_entry(b, struct libscols_line, ln_children);
+ ca = scols_line_get_cell(ra, cl->seqnum);
+ cb = scols_line_get_cell(rb, cl->seqnum);
+
+ return cl->cmpfunc(ca, cb, cl->cmpfunc_data);
+}
+
+
+static int sort_line_children(struct libscols_line *ln, struct libscols_column *cl)
+{
+ struct list_head *p;
+
+ if (!list_empty(&ln->ln_branch)) {
+ list_for_each(p, &ln->ln_branch) {
+ struct libscols_line *chld =
+ list_entry(p, struct libscols_line, ln_children);
+ sort_line_children(chld, cl);
+ }
+
+ list_sort(&ln->ln_branch, cells_cmp_wrapper_children, cl);
+ }
+
+ if (is_first_group_member(ln)) {
+ list_for_each(p, &ln->group->gr_children) {
+ struct libscols_line *chld =
+ list_entry(p, struct libscols_line, ln_children);
+ sort_line_children(chld, cl);
+ }
+
+ list_sort(&ln->group->gr_children, cells_cmp_wrapper_children, cl);
+ }
+
+ return 0;
+}
+
+/**
+ * scols_sort_table:
+ * @tb: table
+ * @cl: order by this column
+ *
+ * Orders the table by the column. See also scols_column_set_cmpfunc(). If the
+ * tree output is enabled then children in the tree are recursively sorted too.
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_sort_table(struct libscols_table *tb, struct libscols_column *cl)
+{
+ if (!tb || !cl || !cl->cmpfunc)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "sorting table"));
+ list_sort(&tb->tb_lines, cells_cmp_wrapper_lines, cl);
+
+ if (scols_table_is_tree(tb)) {
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0)
+ sort_line_children(ln, cl);
+ }
+
+ return 0;
+}
+
+static struct libscols_line *move_line_and_children(struct libscols_line *ln, struct libscols_line *pre)
+{
+ if (pre) {
+ list_del_init(&ln->ln_lines); /* remove from old position */
+ list_add(&ln->ln_lines, &pre->ln_lines); /* add to the new place (behind @pre) */
+ }
+ pre = ln;
+
+ if (!list_empty(&ln->ln_branch)) {
+ struct list_head *p;
+
+ list_for_each(p, &ln->ln_branch) {
+ struct libscols_line *chld =
+ list_entry(p, struct libscols_line, ln_children);
+ pre = move_line_and_children(chld, pre);
+ }
+ }
+
+ return pre;
+}
+
+/**
+ * scols_sort_table_by_tree:
+ * @tb: table
+ *
+ * Reorders lines in the table by parent->child relation. Note that order of
+ * the lines in the table is independent on the tree hierarchy.
+ *
+ * Since: 2.30
+ *
+ * Returns: 0, a negative value in case of an error.
+ */
+int scols_sort_table_by_tree(struct libscols_table *tb)
+{
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+
+ if (!tb)
+ return -EINVAL;
+
+ DBG(TAB, ul_debugobj(tb, "sorting table by tree"));
+
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->parent)
+ continue;
+
+ move_line_and_children(ln, NULL);
+ }
+
+ return 0;
+}
+
+
+/**
+ * scols_table_set_termforce:
+ * @tb: table
+ * @force: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO}
+ *
+ * Forces library to use stdout as terminal, non-terminal or use automatic
+ * detection (default).
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_table_set_termforce(struct libscols_table *tb, int force)
+{
+ if (!tb)
+ return -EINVAL;
+ tb->termforce = force;
+ return 0;
+}
+
+/**
+ * scols_table_get_termforce:
+ * @tb: table
+ *
+ * Returns: SCOLS_TERMFORCE_{NEVER,ALWAYS,AUTO} or a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_table_get_termforce(const struct libscols_table *tb)
+{
+ return tb->termforce;
+}
+
+/**
+ * scols_table_set_termwidth
+ * @tb: table
+ * @width: terminal width
+ *
+ * The library automatically detects terminal width or defaults to 80 chars if
+ * detections is unsuccessful. This function override this behaviour.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.29
+ */
+int scols_table_set_termwidth(struct libscols_table *tb, size_t width)
+{
+ DBG(TAB, ul_debugobj(tb, "set terminatl width: %zu", width));
+ tb->termwidth = width;
+ return 0;
+}
+
+/**
+ * scols_table_get_termwidth
+ * @tb: table
+ *
+ * Returns: terminal width.
+ */
+size_t scols_table_get_termwidth(const struct libscols_table *tb)
+{
+ return tb->termwidth;
+}
+
+/**
+ * scols_table_set_termheight
+ * @tb: table
+ * @height: terminal height (number of lines)
+ *
+ * The library automatically detects terminal height or defaults to 24 lines if
+ * detections is unsuccessful. This function override this behaviour.
+ *
+ * Returns: 0, a negative value in case of an error.
+ *
+ * Since: 2.31
+ */
+int scols_table_set_termheight(struct libscols_table *tb, size_t height)
+{
+ DBG(TAB, ul_debugobj(tb, "set terminatl height: %zu", height));
+ tb->termheight = height;
+ return 0;
+}
+
+/**
+ * scols_table_get_termheight
+ * @tb: table
+ *
+ * Returns: terminal height (number of lines).
+ *
+ * Since: 2.31
+ */
+size_t scols_table_get_termheight(const struct libscols_table *tb)
+{
+ return tb->termheight;
+}
diff --git a/src/utils/libsmartcols/src/version.c b/src/utils/libsmartcols/src/version.c
new file mode 100644
index 0000000..e592ccc
--- /dev/null
+++ b/src/utils/libsmartcols/src/version.c
@@ -0,0 +1,62 @@
+/*
+ * version.c - Return the version of the library
+ *
+ * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *
+ * See COPYING.libmount for the License of this software.
+ */
+
+/**
+ * SECTION: version-utils
+ * @title: Version functions
+ * @short_description: functions to get the library version.
+ *
+ * Note that library version is not the same thing as SONAME version. The
+ * libsmarcols uses symbols versioning and SONAME is not modified for releases.
+ *
+ * The library version and symbols version follow util-linux package versioning.
+ */
+
+#include <ctype.h>
+
+#include "smartcolsP.h"
+
+static const char *lib_version = LIBSMARTCOLS_VERSION;
+
+/**
+ * scols_parse_version_string:
+ * @ver_string: version string (e.g "2.18.0")
+ *
+ * Returns: release version code.
+ */
+int scols_parse_version_string(const char *ver_string)
+{
+ const char *cp;
+ int version = 0;
+
+ assert(ver_string);
+
+ for (cp = ver_string; *cp; cp++) {
+ if (*cp == '.')
+ continue;
+ if (!isdigit(*cp))
+ break;
+ version = (version * 10) + (*cp - '0');
+ }
+ return version;
+}
+
+/**
+ * scols_get_library_version:
+ * @ver_string: return pointer to the static library version string if not NULL
+ *
+ * Returns: release version number.
+ */
+int scols_get_library_version(const char **ver_string)
+{
+ if (ver_string)
+ *ver_string = lib_version;
+
+ return scols_parse_version_string(lib_version);
+}
+
diff --git a/src/utils/libsmartcols/src/walk.c b/src/utils/libsmartcols/src/walk.c
new file mode 100644
index 0000000..a75fde6
--- /dev/null
+++ b/src/utils/libsmartcols/src/walk.c
@@ -0,0 +1,152 @@
+#include "smartcolsP.h"
+
+static int walk_line(struct libscols_table *tb,
+ struct libscols_line *ln,
+ struct libscols_column *cl,
+ int (*callback)(struct libscols_table *,
+ struct libscols_line *,
+ struct libscols_column *,
+ void *),
+ void *data)
+{
+ int rc = 0;
+
+ DBG(LINE, ul_debugobj(ln, " wall line"));
+
+ /* we list group children in __scols_print_tree() after tree root node */
+ if (is_group_member(ln) && is_last_group_member(ln) && has_group_children(ln))
+ tb->ngrpchlds_pending++;
+
+ if (has_groups(tb))
+ rc = scols_groups_update_grpset(tb, ln);
+ if (rc == 0)
+ rc = callback(tb, ln, cl, data);
+
+ /* children */
+ if (rc == 0 && has_children(ln)) {
+ struct list_head *p;
+
+ DBG(LINE, ul_debugobj(ln, " children walk"));
+
+ list_for_each(p, &ln->ln_branch) {
+ struct libscols_line *chld = list_entry(p,
+ struct libscols_line, ln_children);
+
+ rc = walk_line(tb, chld, cl, callback, data);
+ if (rc)
+ break;
+ }
+ }
+
+ DBG(LINE, ul_debugobj(ln, "<- walk line done [rc=%d]", rc));
+ return rc;
+}
+
+/* last line in the tree? */
+int scols_walk_is_last(struct libscols_table *tb, struct libscols_line *ln)
+{
+ if (tb->walk_last_done == 0)
+ return 0;
+ if (tb->ngrpchlds_pending > 0)
+ return 0;
+ if (has_children(ln))
+ return 0;
+ if (is_tree_root(ln) && !is_last_tree_root(tb, ln))
+ return 0;
+ if (is_group_member(ln) && (!is_last_group_member(ln) || has_group_children(ln)))
+ return 0;
+ if (is_child(ln)) {
+ struct libscols_line *parent = ln->parent;
+
+ if (!is_last_child(ln))
+ return 0;
+ while (parent) {
+ if (is_child(parent) && !is_last_child(parent))
+ return 0;
+ if (!parent->parent)
+ break;
+ parent = parent->parent;
+ }
+ if (is_tree_root(parent) && !is_last_tree_root(tb, parent))
+ return 0;
+ }
+ if (is_group_child(ln) && !is_last_group_child(ln))
+ return 0;
+
+ DBG(LINE, ul_debugobj(ln, "last in table"));
+ return 1;
+}
+
+int scols_walk_tree(struct libscols_table *tb,
+ struct libscols_column *cl,
+ int (*callback)(struct libscols_table *,
+ struct libscols_line *,
+ struct libscols_column *,
+ void *),
+ void *data)
+{
+ int rc = 0;
+ struct libscols_line *ln;
+ struct libscols_iter itr;
+
+ assert(tb);
+ DBG(TAB, ul_debugobj(tb, ">> walk start"));
+
+ /* init */
+ tb->ngrpchlds_pending = 0;
+ tb->walk_last_tree_root = NULL;
+ tb->walk_last_done = 0;
+
+ if (has_groups(tb))
+ scols_groups_reset_state(tb);
+
+ /* set pointer to last tree root */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (!tb->walk_last_tree_root)
+ tb->walk_last_tree_root = ln;
+ if (is_child(ln) || is_group_child(ln))
+ continue;
+ tb->walk_last_tree_root = ln;
+ }
+
+ /* walk */
+ scols_reset_iter(&itr, SCOLS_ITER_FORWARD);
+ while (rc == 0 && scols_table_next_line(tb, &itr, &ln) == 0) {
+ if (ln->parent || ln->parent_group)
+ continue;
+
+ if (tb->walk_last_tree_root == ln)
+ tb->walk_last_done = 1;
+ rc = walk_line(tb, ln, cl, callback, data);
+
+ /* walk group's children */
+ while (rc == 0 && tb->ngrpchlds_pending) {
+ struct libscols_group *gr = scols_grpset_get_printable_children(tb);
+ struct list_head *p;
+
+ DBG(LINE, ul_debugobj(ln, " walk group children [pending=%zu]", tb->ngrpchlds_pending));
+ if (!gr) {
+ DBG(LINE, ul_debugobj(ln, " *** ngrpchlds_pending counter invalid"));
+ tb->ngrpchlds_pending = 0;
+ break;
+ }
+
+ tb->ngrpchlds_pending--;
+
+ list_for_each(p, &gr->gr_children) {
+ struct libscols_line *chld =
+ list_entry(p, struct libscols_line, ln_children);
+
+ rc = walk_line(tb, chld, cl, callback, data);
+ if (rc)
+ break;
+ }
+ }
+ }
+
+ tb->ngrpchlds_pending = 0;
+ tb->walk_last_done = 0;
+ DBG(TAB, ul_debugobj(tb, "<< walk end [rc=%d]", rc));
+ return rc;
+}
diff --git a/src/utils/sys-utils/CMakeLists.txt b/src/utils/sys-utils/CMakeLists.txt
new file mode 100644
index 0000000..01295d9
--- /dev/null
+++ b/src/utils/sys-utils/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.10)
+
+# set the project name
+project(xloop-utils-sys-utils)
+
+# add xlosetup executable
+add_executable(xlosetup ${CMAKE_CURRENT_SOURCE_DIR}/xlosetup.c)
+target_link_libraries(xlosetup LINK_PUBLIC libcommon libsmartcols)
+target_include_directories(xlosetup PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../libsmartcols)
+install(TARGETS xlosetup DESTINATION bin
+ COMPONENT main)
+
+# install xlosetup man page
+# NOTE: installation is done via a directory install with file matching pattern to support CPackRPM's automatic compression of man pages
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
+ DESTINATION share/man/man8
+ COMPONENT main
+ USE_SOURCE_PERMISSIONS
+ FILES_MATCHING PATTERN *.8*)
diff --git a/src/utils/sys-utils/xlosetup.8 b/src/utils/sys-utils/xlosetup.8
new file mode 100644
index 0000000..4e063e6
--- /dev/null
+++ b/src/utils/sys-utils/xlosetup.8
@@ -0,0 +1,215 @@
+.TH XLOSETUP 8 "September 2020" "util-linux" "System Administration"
+.SH NAME
+xlosetup \- set up and control xloop devices
+.SH SYNOPSIS
+.ad l
+Get info:
+.sp
+.in +5
+.B xlosetup
+[\fIxloopdev\fP]
+.sp
+.B xlosetup \-l
+.RB [ \-a ]
+.sp
+.B xlosetup \-j
+.I file
+.RB [ \-o
+.IR offset ]
+.sp
+.in -5
+Detach a xloop device:
+.sp
+.in +5
+.B "xlosetup \-d"
+.IR xloopdev ...
+.sp
+.in -5
+Detach all associated xloop devices:
+.sp
+.in +5
+.B "xlosetup \-D"
+.sp
+.in -5
+Set up a xloop device:
+.sp
+.in +5
+.B xlosetup
+.RB [ \-o
+.IR offset ]
+.RB [ \-\-sizelimit
+.IR size ]
+.RB [ \-\-sector\-size
+.IR size ]
+.in +8
+.RB [ \-Pr ]
+.RB [ \-\-show ] " \-f" | \fIxloopdev\fP
+.I file
+.sp
+.in -13
+Resize a xloop device:
+.sp
+.in +5
+.B "xlosetup \-c"
+.I xloopdev
+.in -5
+.ad b
+.SH DESCRIPTION
+.B xlosetup
+is used to associate xloop devices with regular files or block devices,
+to detach xloop devices, and to query the status of a xloop device. If only the
+\fIxloopdev\fP argument is given, the status of the corresponding xloop
+device is shown. If no option is given, all xloop devices are shown.
+.sp
+Note that the old output format (i.e., \fBxlosetup \-a\fR) with comma-delimited
+strings is deprecated in favour of the \fB\-\-list\fR output format.
+.sp
+It's possible to create more independent xloop devices for the same backing
+file.
+.B This setup may be dangerous, can cause data loss, corruption and overwrites.
+Use \fB\-\-nooverlap\fR with \fB\-\-find\fR during setup to avoid this problem.
+
+.SH OPTIONS
+The \fIsize\fR and \fIoffset\fR
+arguments may be followed by the multiplicative suffixes KiB (=1024),
+MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB (the "iB" is
+optional, e.g., "K" has the same meaning as "KiB") or the suffixes
+KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB.
+
+.TP
+.BR \-a , " \-\-all"
+Show the status of all xloop devices. Note that not all information is accessible
+for non-root users. See also \fB\-\-list\fR. The old output format (as printed
+without \fB\-\-list)\fR is deprecated.
+.TP
+.BR \-d , " \-\-detach " \fIxloopdev\fR...
+Detach the file or device associated with the specified xloop device(s). Note
+that since Linux v3.7 kernel uses "lazy device destruction". The detach
+operation does not return EBUSY error anymore if device is actively used by
+system, but it is marked by autoclear flag and destroyed later.
+.TP
+.BR \-D , " \-\-detach\-all"
+Detach all associated xloop devices.
+.TP
+.BR \-f , " \-\-find " "\fR[\fIfile\fR]"
+Find the first unused xloop device. If a \fIfile\fR argument is present, use
+the found device as xloop device. Otherwise, just print its name.
+.IP "\fB\-\-show\fP"
+Display the name of the assigned xloop device if the \fB\-f\fP option and a
+\fIfile\fP argument are present.
+.TP
+.BR \-L , " \-\-nooverlap"
+Check for conflicts between xloop devices to avoid situation when the same
+backing file is shared between more xloop devices. If the file is already used
+by another device then re-use the device rather than a new one. The option
+makes sense only with \fB\-\-find\fP.
+.TP
+.BR \-j , " \-\-associated " \fIfile\fR " \fR[\fB\-o \fIoffset\fR]"
+Show the status of all xloop devices associated with the given \fIfile\fR.
+.TP
+.BR \-o , " \-\-offset " \fIoffset
+The data start is moved \fIoffset\fP bytes into the specified file or device. The \fIoffset\fP
+may be followed by the multiplicative suffixes; see above.
+.IP "\fB\-\-sizelimit \fIsize\fP"
+The data end is set to no more than \fIsize\fP bytes after the data start. The \fIsize\fP
+may be followed by the multiplicative suffixes; see above.
+.TP
+.BR \-b , " \-\-sector-size " \fIsize
+Set the logical sector size of the xloop device in bytes (since Linux 4.14). The
+option may be used when create a new xloop device as well as stand-alone command
+to modify sector size of the already existing xloop device.
+.TP
+.BR \-c , " \-\-set\-capacity " \fIxloopdev
+Force the xloop driver to reread the size of the file associated with the
+specified xloop device.
+.TP
+.BR \-P , " \-\-partscan"
+Force the kernel to scan the partition table on a newly created xloop device. Note that the
+partition table parsing depends on sector sizes. The default is sector size is 512 bytes,
+otherwise you need to use the option \fB\-\-sector\-size\fR together with \fB\-\-partscan\fR.
+.TP
+.BR \-r , " \-\-read\-only"
+Set up a read-only xloop device.
+.TP
+.BR \-\-direct\-io [ =on | off ]
+Enable or disable direct I/O for the backing file. The optional argument
+can be either \fBon\fR or \fBoff\fR. If the argument is omitted, it defaults
+to \fBoff\fR.
+.TP
+.BR \-t , " \-\-type \fIformat\fR"
+Set the file format type of the xloop device. If no file format type is specified,
+the RAW file format is used by default. Valid file formats are: \fBRAW\fR,
+\fBQCOW\fR, \fBVDI\fR, \fBVMDK\fR.
+.TP
+.BR \-v , " \-\-verbose"
+Verbose mode.
+.TP
+.BR \-l , " \-\-list"
+If a xloop device or the \fB\-a\fR option is specified, print the default columns
+for either the specified xloop device or all xloop devices; the default is to
+print info about all devices. See also \fB\-\-output\fP, \fB\-\-noheadings\fP,
+\fB\-\-raw\fP, and \fB\-\-json\fP.
+.TP
+.BR \-O , " \-\-output " \fIcolumn\fR[,\fIcolumn\fR]...
+Specify the columns that are to be printed for the \fB\-\-list\fP output.
+Use \fB\-\-help\fR to get a list of all supported columns.
+.TP
+.B \-\-output\-all
+Output all available columns.
+.TP
+.BR \-n , " \-\-noheadings"
+Don't print headings for \fB\-\-list\fP output format.
+.IP "\fB\-\-raw\fP"
+Use the raw \fB\-\-list\fP output format.
+.TP
+.BR \-J , " \-\-json"
+Use JSON format for \fB\-\-list\fP output.
+.TP
+.BR \-V , " \-\-version"
+Display version information and exit.
+.TP
+.BR \-h , " \-\-help"
+Display help text and exit.
+
+.SH ENCRYPTION
+.B Cryptoloop is no longer supported in favor of dm-crypt.
+.B For more details see cryptsetup(8).
+
+.SH EXIT STATUS
+.B xlosetup
+returns 0 on success, nonzero on failure. When
+.B xlosetup
+displays the status of a xloop device, it returns 1 if the device
+is not configured and 2 if an error occurred which prevented
+determining the status of the device.
+
+.SH ENVIRONMENT
+.IP XLOOPDEV_DEBUG=all
+enables debug output.
+
+.SH FILES
+.TP
+.I /dev/xloop[0..N]
+xloop block devices
+.TP
+.I /dev/xloop-control
+xloop control device
+.SH EXAMPLE
+The following commands can be used as an example of using the xloop device.
+.nf
+.IP
+# dd if=/dev/zero of=~/file.img bs=1024k count=10
+# xlosetup \-\-find \-\-show ~/file.img
+/dev/xloop0
+# mkfs \-t ext2 /dev/xloop0
+# mount /dev/xloop0 /mnt
+ ...
+# umount /dev/xloop0
+# xlosetup \-\-detach /dev/xloop0
+.fi
+.SH AUTHORS
+Karel Zak <kzak@redhat.com>, based on the original version from
+Theodore Ts'o <tytso@athena.mit.edu>
+.SH AVAILABILITY
+The xlosetup command is part of the util-linux package and is available from
+https://www.kernel.org/pub/linux/utils/util-linux/.
diff --git a/src/utils/sys-utils/xlosetup.c b/src/utils/sys-utils/xlosetup.c
new file mode 100644
index 0000000..60fa0ba
--- /dev/null
+++ b/src/utils/sys-utils/xlosetup.c
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ * Originally from Ted's losetup.c
+ *
+ * xlosetup.c - setup and control xloop devices
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <libsmartcols.h>
+
+#include "c.h"
+#include "nls.h"
+#include "strutils.h"
+#include "loopdev.h"
+#include "closestream.h"
+#include "optutils.h"
+#include "xalloc.h"
+#include "canonicalize.h"
+#include "pathnames.h"
+
+enum {
+ A_CREATE = 1, /* setup a new device */
+ A_DELETE, /* delete given device(s) */
+ A_DELETE_ALL, /* delete all devices */
+ A_SHOW, /* list devices */
+ A_SHOW_ONE, /* print info about one device */
+ A_FIND_FREE, /* find first unused */
+ A_SET_CAPACITY, /* set device capacity */
+ A_SET_DIRECT_IO, /* set accessing backing file by direct io */
+ A_SET_BLOCKSIZE, /* set logical block size of the xloop device */
+};
+
+enum {
+ COL_NAME = 0,
+ COL_AUTOCLR,
+ COL_BACK_FILE,
+ COL_FILE_FMT_TYPE,
+ COL_BACK_INO,
+ COL_BACK_MAJMIN,
+ COL_MAJMIN,
+ COL_OFFSET,
+ COL_PARTSCAN,
+ COL_RO,
+ COL_SIZELIMIT,
+ COL_DIO,
+ COL_LOGSEC,
+};
+
+/* basic output flags */
+static int no_headings;
+static int raw;
+static int json;
+
+struct colinfo {
+ const char *name;
+ double whint;
+ int flags;
+ const char *help;
+
+ int json_type; /* default is string */
+};
+
+static struct colinfo infos[] = {
+ [COL_AUTOCLR] = { "AUTOCLEAR", 1, SCOLS_FL_RIGHT, N_("autoclear flag set"), SCOLS_JSON_BOOLEAN},
+ [COL_BACK_FILE] = { "BACK-FILE", 0.3, 0, N_("device backing file")},
+ [COL_FILE_FMT_TYPE] = { "FILE-FORMAT", 1, 0, N_("backing file format")},
+ [COL_BACK_INO] = { "BACK-INO", 4, SCOLS_FL_RIGHT, N_("backing file inode number"), SCOLS_JSON_NUMBER},
+ [COL_BACK_MAJMIN] = { "BACK-MAJ:MIN", 6, 0, N_("backing file major:minor device number")},
+ [COL_NAME] = { "NAME", 0.25, 0, N_("xloop device name")},
+ [COL_OFFSET] = { "OFFSET", 5, SCOLS_FL_RIGHT, N_("offset from the beginning"), SCOLS_JSON_NUMBER},
+ [COL_PARTSCAN] = { "PARTSCAN", 1, SCOLS_FL_RIGHT, N_("partscan flag set"), SCOLS_JSON_BOOLEAN},
+ [COL_RO] = { "RO", 1, SCOLS_FL_RIGHT, N_("read-only device"), SCOLS_JSON_BOOLEAN},
+ [COL_SIZELIMIT] = { "SIZELIMIT", 5, SCOLS_FL_RIGHT, N_("size limit of the file in bytes"), SCOLS_JSON_NUMBER},
+ [COL_MAJMIN] = { "MAJ:MIN", 3, 0, N_("xloop device major:minor number")},
+ [COL_DIO] = { "DIO", 1, SCOLS_FL_RIGHT, N_("access backing file with direct-io"), SCOLS_JSON_BOOLEAN},
+ [COL_LOGSEC] = { "LOG-SEC", 4, SCOLS_FL_RIGHT, N_("logical sector size in bytes"), SCOLS_JSON_NUMBER},
+};
+
+static int columns[ARRAY_SIZE(infos) * 2] = {-1};
+static size_t ncolumns;
+
+static int get_column_id(int num)
+{
+ assert(num >= 0);
+ assert((size_t) num < ncolumns);
+ assert(columns[num] < (int) ARRAY_SIZE(infos));
+ return columns[num];
+}
+
+static struct colinfo *get_column_info(int num)
+{
+ return &infos[ get_column_id(num) ];
+}
+
+static int column_name_to_id(const char *name, size_t namesz)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(infos); i++) {
+ const char *cn = infos[i].name;
+
+ if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+ return i;
+ }
+ warnx(_("unknown column: %s"), name);
+ return -1;
+}
+
+static int printf_loopdev(struct loopdev_cxt *lc)
+{
+ uint64_t x;
+ dev_t dev = 0;
+ ino_t ino = 0;
+ char *fname;
+ uint32_t type;
+ char *file_fmt_str;
+
+ fname = loopcxt_get_backing_file(lc);
+ if (!fname)
+ return -EINVAL;
+
+ file_fmt_str = loopcxt_get_file_fmt_type_string(lc);
+ if (!file_fmt_str)
+ return -EINVAL;
+
+ if (loopcxt_get_backing_devno(lc, &dev) == 0)
+ loopcxt_get_backing_inode(lc, &ino);
+
+ if (!dev && !ino) {
+ /*
+ * Probably non-root user (no permissions to
+ * call LOOP_GET_STATUS ioctls).
+ */
+ printf("%s: []: (%s)",
+ loopcxt_get_device(lc), fname);
+
+ if (loopcxt_get_offset(lc, &x) == 0 && x)
+ printf(_(", offset %ju"), x);
+
+ if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
+ printf(_(", sizelimit %ju"), x);
+
+ printf(_(", file-format %s"), file_fmt_str);
+
+ goto done;
+ }
+
+ printf("%s: [%04d]:%" PRIu64 " (%s)",
+ loopcxt_get_device(lc), (int) dev, ino, fname);
+
+ if (loopcxt_get_offset(lc, &x) == 0 && x)
+ printf(_(", offset %ju"), x);
+
+ if (loopcxt_get_sizelimit(lc, &x) == 0 && x)
+ printf(_(", sizelimit %ju"), x);
+
+ if (loopcxt_get_encrypt_type(lc, &type) == 0) {
+ const char *e = loopcxt_get_crypt_name(lc);
+
+ if ((!e || !*e) && type == 1)
+ e = "XOR";
+ if (e && *e)
+ printf(_(", encryption %s (type %u)"), e, type);
+ }
+
+ printf(_(", file-format %s"), file_fmt_str);
+
+done:
+ free(fname);
+ printf("\n");
+ return 0;
+}
+
+static int show_all_loops(struct loopdev_cxt *lc, const char *file,
+ uint64_t offset, int flags)
+{
+ struct stat sbuf, *st = &sbuf;
+ char *cn_file = NULL;
+
+ if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
+ return -1;
+
+ if (!file || stat(file, st))
+ st = NULL;
+
+ while (loopcxt_next(lc) == 0) {
+ if (file) {
+ int used;
+ const char *bf = cn_file ? cn_file : file;
+
+ used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
+ if (!used && !cn_file) {
+ bf = cn_file = canonicalize_path(file);
+ used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
+ }
+ if (!used)
+ continue;
+ }
+ printf_loopdev(lc);
+ }
+ loopcxt_deinit_iterator(lc);
+ free(cn_file);
+ return 0;
+}
+
+static int delete_loop(struct loopdev_cxt *lc)
+{
+ if (loopcxt_delete_device(lc))
+ warn(_("%s: detach failed"), loopcxt_get_device(lc));
+ else
+ return 0;
+
+ return -1;
+}
+
+static int delete_all_loops(struct loopdev_cxt *lc)
+{
+ int res = 0;
+
+ if (loopcxt_init_iterator(lc, LOOPITER_FL_USED))
+ return -1;
+
+ while (loopcxt_next(lc) == 0)
+ res += delete_loop(lc);
+
+ loopcxt_deinit_iterator(lc);
+ return res;
+}
+
+static int set_scols_data(struct loopdev_cxt *lc, struct libscols_line *ln)
+{
+ size_t i;
+
+ for (i = 0; i < ncolumns; i++) {
+ const char *p = NULL; /* external data */
+ char *np = NULL; /* allocated here */
+ uint64_t x = 0;
+ int rc = 0;
+
+ switch(get_column_id(i)) {
+ case COL_NAME:
+ p = loopcxt_get_device(lc);
+ break;
+ case COL_BACK_FILE:
+ p = loopcxt_get_backing_file(lc);
+ break;
+ case COL_FILE_FMT_TYPE:
+ p = loopcxt_get_file_fmt_type_string(lc);
+ break;
+ case COL_OFFSET:
+ if (loopcxt_get_offset(lc, &x) == 0)
+ xasprintf(&np, "%jd", x);
+ break;
+ case COL_SIZELIMIT:
+ if (loopcxt_get_sizelimit(lc, &x) == 0)
+ xasprintf(&np, "%jd", x);
+ break;
+ case COL_BACK_MAJMIN:
+ {
+ dev_t dev = 0;
+ if (loopcxt_get_backing_devno(lc, &dev) == 0 && dev)
+ xasprintf(&np, "%8u:%-3u", major(dev), minor(dev));
+ break;
+ }
+ case COL_MAJMIN:
+ {
+ struct stat st;
+
+ if (loopcxt_get_device(lc)
+ && stat(loopcxt_get_device(lc), &st) == 0
+ && S_ISBLK(st.st_mode)
+ && major(st.st_rdev) == LOOPDEV_MAJOR)
+ xasprintf(&np, "%3u:%-3u", major(st.st_rdev),
+ minor(st.st_rdev));
+ break;
+ }
+ case COL_BACK_INO:
+ {
+ ino_t ino = 0;
+ if (loopcxt_get_backing_inode(lc, &ino) == 0 && ino)
+ xasprintf(&np, "%ju", ino);
+ break;
+ }
+ case COL_AUTOCLR:
+ p = loopcxt_is_autoclear(lc) ? "1" : "0";
+ break;
+ case COL_RO:
+ p = loopcxt_is_readonly(lc) ? "1" : "0";
+ break;
+ case COL_DIO:
+ p = loopcxt_is_dio(lc) ? "1" : "0";
+ break;
+ case COL_PARTSCAN:
+ p = loopcxt_is_partscan(lc) ? "1" : "0";
+ break;
+ case COL_LOGSEC:
+ if (loopcxt_get_blocksize(lc, &x) == 0)
+ xasprintf(&np, "%jd", x);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ if (p)
+ rc = scols_line_set_data(ln, i, p); /* calls strdup() */
+ else if (np)
+ rc = scols_line_refer_data(ln, i, np); /* only refers */
+
+ if (rc)
+ err(EXIT_FAILURE, _("failed to add output data"));
+ }
+
+ return 0;
+}
+
+static int show_table(struct loopdev_cxt *lc,
+ const char *file,
+ uint64_t offset,
+ int flags)
+{
+ struct stat sbuf, *st = &sbuf;
+ struct libscols_table *tb;
+ struct libscols_line *ln;
+ int rc = 0;
+ size_t i;
+
+ scols_init_debug(0);
+
+ if (!(tb = scols_new_table()))
+ err(EXIT_FAILURE, _("failed to allocate output table"));
+ scols_table_enable_raw(tb, raw);
+ scols_table_enable_json(tb, json);
+ scols_table_enable_noheadings(tb, no_headings);
+
+ if (json)
+ scols_table_set_name(tb, "xloopdevices");
+
+ for (i = 0; i < ncolumns; i++) {
+ struct colinfo *ci = get_column_info(i);
+ struct libscols_column *cl;
+
+ cl = scols_table_new_column(tb, ci->name, ci->whint, ci->flags);
+ if (!cl)
+ err(EXIT_FAILURE, _("failed to allocate output column"));
+ if (json)
+ scols_column_set_json_type(cl, ci->json_type);
+ }
+
+ /* only one xloopdev requested (already assigned to loopdev_cxt) */
+ if (loopcxt_get_device(lc)) {
+ ln = scols_table_new_line(tb, NULL);
+ if (!ln)
+ err(EXIT_FAILURE, _("failed to allocate output line"));
+ rc = set_scols_data(lc, ln);
+
+ /* list all xloopdevs */
+ } else {
+ char *cn_file = NULL;
+
+ rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
+ if (rc)
+ goto done;
+ if (!file || stat(file, st))
+ st = NULL;
+
+ while (loopcxt_next(lc) == 0) {
+ if (file) {
+ int used;
+ const char *bf = cn_file ? cn_file : file;
+
+ used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
+ if (!used && !cn_file) {
+ bf = cn_file = canonicalize_path(file);
+ used = loopcxt_is_used(lc, st, bf, offset, 0, flags);
+ }
+ if (!used)
+ continue;
+ }
+
+ ln = scols_table_new_line(tb, NULL);
+ if (!ln)
+ err(EXIT_FAILURE, _("failed to allocate output line"));
+ rc = set_scols_data(lc, ln);
+ if (rc)
+ break;
+ }
+
+ loopcxt_deinit_iterator(lc);
+ free(cn_file);
+ }
+done:
+ if (rc == 0)
+ rc = scols_print_table(tb);
+ scols_unref_table(tb);
+ return rc;
+}
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ FILE *out = stdout;
+ size_t i;
+
+ fputs(USAGE_HEADER, out);
+
+ fprintf(out,
+ _(" %1$s [options] [<xloopdev>]\n"
+ " %1$s [options] -f | <xloopdev> <file>\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_("Set up and control xloop devices.\n"), out);
+
+ /* commands */
+ fputs(USAGE_OPTIONS, out);
+ fputs(_(" -a, --all list all used devices\n"), out);
+ fputs(_(" -d, --detach <xloopdev>... detach one or more devices\n"), out);
+ fputs(_(" -D, --detach-all detach all used devices\n"), out);
+ fputs(_(" -f, --find find first unused device\n"), out);
+ fputs(_(" -c, --set-capacity <xloopdev> resize the device\n"), out);
+ fputs(_(" -j, --associated <file> list all devices associated with <file>\n"), out);
+ fputs(_(" -L, --nooverlap avoid possible conflict between devices\n"), out);
+
+ /* commands options */
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_(" -o, --offset <num> start at offset <num> into file\n"), out);
+ fputs(_(" --sizelimit <num> device is limited to <num> bytes of the file\n"), out);
+ fputs(_(" -b, --sector-size <num> set the logical sector size to <num>\n"), out);
+ fputs(_(" -P, --partscan create a partitioned xloop device\n"), out);
+ fputs(_(" -r, --read-only set up a read-only xloop device\n"), out);
+ fputs(_(" --direct-io[=<on|off>] open backing file with O_DIRECT\n"), out);
+ fputs(_(" --show print device name after setup (with -f)\n"), out);
+ fputs(_(" -t, --type set file format type of the loop device\n"), out);
+ fputs(_(" -v, --verbose verbose mode\n"), out);
+
+ /* output options */
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_(" -J, --json use JSON --list output format\n"), out);
+ fputs(_(" -l, --list list info about all or specified (default)\n"), out);
+ fputs(_(" -n, --noheadings don't print headings for --list output\n"), out);
+ fputs(_(" -O, --output <cols> specify columns to output for --list\n"), out);
+ fputs(_(" --output-all output all columns\n"), out);
+ fputs(_(" --raw use raw --list output format\n"), out);
+
+ fputs(USAGE_SEPARATOR, out);
+ printf(USAGE_HELP_OPTIONS(31));
+
+ fputs(USAGE_COLUMNS, out);
+ for (i = 0; i < ARRAY_SIZE(infos); i++)
+ fprintf(out, " %12s %s\n", infos[i].name, _(infos[i].help));
+
+ printf(USAGE_MAN_TAIL("xlosetup(8)"));
+
+ exit(EXIT_SUCCESS);
+}
+
+static int create_loop(struct loopdev_cxt *lc,
+ int nooverlap, int lo_flags, int flags,
+ const char *file, uint64_t offset, uint64_t sizelimit,
+ uint64_t blocksize, uint32_t file_fmt_type)
+{
+ int hasdev = loopcxt_has_device(lc);
+ int rc = 0;
+
+ /* xlosetup --find --noverlap file.img */
+ if (!hasdev && nooverlap) {
+ rc = loopcxt_find_overlap(lc, file, offset, sizelimit);
+ switch (rc) {
+ case 0: /* not found */
+ break;
+
+ case 1: /* overlap */
+ loopcxt_deinit(lc);
+ errx(EXIT_FAILURE, _("%s: overlapping xloop device exists"), file);
+
+ case 2: /* overlap -- full size and offset match (reuse) */
+ {
+ uint32_t lc_encrypt_type;
+
+ /* Once a xloop is initialized RO, there is no
+ * way to change its parameters. */
+ if (loopcxt_is_readonly(lc)
+ && !(lo_flags & LO_FLAGS_READ_ONLY)) {
+ loopcxt_deinit(lc);
+ errx(EXIT_FAILURE, _("%s: overlapping read-only xloop device exists"), file);
+ }
+
+ /* This is no more supported, but check to be safe. */
+ if (loopcxt_get_encrypt_type(lc, &lc_encrypt_type) == 0
+ && lc_encrypt_type != LO_CRYPT_NONE) {
+ loopcxt_deinit(lc);
+ errx(EXIT_FAILURE, _("%s: overlapping encrypted xloop device exists"), file);
+ }
+
+ lc->info.lo_flags &= ~LO_FLAGS_AUTOCLEAR;
+ if (loopcxt_ioctl_status(lc)) {
+ loopcxt_deinit(lc);
+ errx(EXIT_FAILURE, _("%s: failed to re-use xloop device"), file);
+ }
+ return 0; /* success, re-use */
+ }
+ default: /* error */
+ loopcxt_deinit(lc);
+ errx(EXIT_FAILURE, _("failed to inspect xloop devices"));
+ return -errno;
+ }
+ }
+
+ if (hasdev && !is_loopdev(loopcxt_get_device(lc)))
+ loopcxt_add_device(lc);
+
+ /* xlosetup --noverlap /dev/xloopN file.img */
+ if (hasdev && nooverlap) {
+ struct loopdev_cxt lc2;
+
+ if (loopcxt_init(&lc2, 0)) {
+ loopcxt_deinit(lc);
+ err(EXIT_FAILURE, _("failed to initialize loopcxt"));
+ }
+ rc = loopcxt_find_overlap(&lc2, file, offset, sizelimit);
+ loopcxt_deinit(&lc2);
+
+ if (rc) {
+ loopcxt_deinit(lc);
+ if (rc > 0)
+ errx(EXIT_FAILURE, _("%s: overlapping xloop device exists"), file);
+ err(EXIT_FAILURE, _("%s: failed to check for conflicting xloop devices"), file);
+ }
+ }
+
+ /* Create a new device */
+ do {
+ const char *errpre;
+
+ /* Note that loopcxt_{find_unused,set_device}() resets
+ * loopcxt struct.
+ */
+ if (!hasdev && (rc = loopcxt_find_unused(lc))) {
+ warnx(_("cannot find an unused xloop device"));
+ break;
+ }
+ if (flags & LOOPDEV_FL_OFFSET)
+ loopcxt_set_offset(lc, offset);
+ if (flags & LOOPDEV_FL_SIZELIMIT)
+ loopcxt_set_sizelimit(lc, sizelimit);
+ if (lo_flags)
+ loopcxt_set_flags(lc, lo_flags);
+ if (blocksize > 0)
+ loopcxt_set_blocksize(lc, blocksize);
+
+ if ((rc = loopcxt_set_backing_file(lc, file))) {
+ warn(_("%s: failed to use backing file"), file);
+ break;
+ }
+
+ if ((rc = loopcxt_set_file_fmt_type(lc, file_fmt_type))) {
+ warn(_("failed to use backing file format type"));
+ break;
+ }
+
+ errno = 0;
+ rc = loopcxt_setup_device(lc);
+ if (rc == 0)
+ break; /* success */
+ if (errno == EBUSY && !hasdev)
+ continue;
+
+ /* errors */
+ errpre = hasdev && loopcxt_get_fd(lc) < 0 ?
+ loopcxt_get_device(lc) : file;
+ warn(_("%s: failed to set up xloop device"), errpre);
+ break;
+ } while (hasdev == 0);
+
+ return rc;
+}
+
+int main(int argc, char **argv)
+{
+ struct loopdev_cxt lc;
+ int act = 0, flags = 0, no_overlap = 0, c;
+ char *file = NULL;
+ uint64_t offset = 0, sizelimit = 0, blocksize = 0;
+ int res = 0, showdev = 0, lo_flags = 0;
+ char *outarg = NULL;
+ int list = 0;
+ unsigned long use_dio = 0, set_dio = 0, set_blocksize = 0;
+ int use_file_fmt_type = 0;
+ uint32_t file_fmt_type = 0;
+
+ enum {
+ OPT_SIZELIMIT = CHAR_MAX + 1,
+ OPT_SHOW,
+ OPT_RAW,
+ OPT_DIO,
+ OPT_OUTPUT_ALL
+ };
+ static const struct option longopts[] = {
+ { "all", no_argument, NULL, 'a' },
+ { "set-capacity", required_argument, NULL, 'c' },
+ { "detach", required_argument, NULL, 'd' },
+ { "detach-all", no_argument, NULL, 'D' },
+ { "find", no_argument, NULL, 'f' },
+ { "nooverlap", no_argument, NULL, 'L' },
+ { "help", no_argument, NULL, 'h' },
+ { "associated", required_argument, NULL, 'j' },
+ { "json", no_argument, NULL, 'J' },
+ { "list", no_argument, NULL, 'l' },
+ { "sector-size", required_argument, NULL, 'b' },
+ { "noheadings", no_argument, NULL, 'n' },
+ { "offset", required_argument, NULL, 'o' },
+ { "output", required_argument, NULL, 'O' },
+ { "output-all", no_argument, NULL, OPT_OUTPUT_ALL },
+ { "sizelimit", required_argument, NULL, OPT_SIZELIMIT },
+ { "partscan", no_argument, NULL, 'P' },
+ { "read-only", no_argument, NULL, 'r' },
+ { "direct-io", optional_argument, NULL, OPT_DIO },
+ { "raw", no_argument, NULL, OPT_RAW },
+ { "show", no_argument, NULL, OPT_SHOW },
+ { "type", required_argument, NULL, 't' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
+ { 'D','a','c','d','f','j' },
+ { 'D','c','d','f','l' },
+ { 'D','c','d','f','O' },
+ { 'J',OPT_RAW },
+ { 0 }
+ };
+ int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ close_stdout_atexit();
+
+ if (loopcxt_init(&lc, 0))
+ err(EXIT_FAILURE, _("failed to initialize loopcxt"));
+
+ while ((c = getopt_long(argc, argv, "ab:c:d:Dfhj:JlLno:O:Prt:vV",
+ longopts, NULL)) != -1) {
+
+ err_exclusive_options(c, longopts, excl, excl_st);
+
+ switch (c) {
+ case 'a':
+ act = A_SHOW;
+ break;
+ case 'b':
+ set_blocksize = 1;
+ blocksize = strtosize_or_err(optarg, _("failed to parse logical block size"));
+ break;
+ case 'c':
+ act = A_SET_CAPACITY;
+ if (!is_loopdev(optarg) ||
+ loopcxt_set_device(&lc, optarg))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ optarg);
+ break;
+ case 'r':
+ lo_flags |= LO_FLAGS_READ_ONLY;
+ break;
+ case 'd':
+ act = A_DELETE;
+ if (!is_loopdev(optarg) ||
+ loopcxt_set_device(&lc, optarg))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ optarg);
+ break;
+ case 'D':
+ act = A_DELETE_ALL;
+ break;
+ case 'f':
+ act = A_FIND_FREE;
+ break;
+ case 'J':
+ json = 1;
+ break;
+ case 'j':
+ act = A_SHOW;
+ file = optarg;
+ break;
+ case 'l':
+ list = 1;
+ break;
+ case 'L':
+ no_overlap = 1;
+ break;
+ case 'n':
+ no_headings = 1;
+ break;
+ case OPT_RAW:
+ raw = 1;
+ break;
+ case 'o':
+ offset = strtosize_or_err(optarg, _("failed to parse offset"));
+ flags |= LOOPDEV_FL_OFFSET;
+ break;
+ case 'O':
+ outarg = optarg;
+ list = 1;
+ break;
+ case OPT_OUTPUT_ALL:
+ for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
+ columns[ncolumns] = ncolumns;
+ break;
+ case 'P':
+ lo_flags |= LO_FLAGS_PARTSCAN;
+ break;
+ case OPT_SHOW:
+ showdev = 1;
+ break;
+ case OPT_DIO:
+ use_dio = set_dio = 1;
+ if (optarg)
+ use_dio = parse_switch(optarg, _("argument error"), "on", "off", NULL);
+ break;
+ case 't':
+ if (optarg) {
+ if (parse_file_fmt_type(optarg, &file_fmt_type) == 0)
+ use_file_fmt_type = 1;
+ else
+ errx(EXIT_FAILURE, _("failed to parse file format type"));
+ }
+ break;
+ case 'v':
+ break;
+ case OPT_SIZELIMIT: /* --sizelimit */
+ sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
+ flags |= LOOPDEV_FL_SIZELIMIT;
+ break;
+
+ case 'h':
+ usage();
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ default:
+ errtryhelp(EXIT_FAILURE);
+ }
+ }
+
+ ul_path_init_debug();
+ ul_sysfs_init_debug();
+
+ /* default is --list --all */
+ if (argc == 1) {
+ act = A_SHOW;
+ list = 1;
+ }
+
+ if (!act && argc == 2 && (raw || json)) {
+ act = A_SHOW;
+ list = 1;
+ }
+
+ /* default --list output columns */
+ if (list && !ncolumns) {
+ columns[ncolumns++] = COL_NAME;
+ columns[ncolumns++] = COL_SIZELIMIT;
+ columns[ncolumns++] = COL_OFFSET;
+ columns[ncolumns++] = COL_AUTOCLR;
+ columns[ncolumns++] = COL_RO;
+ columns[ncolumns++] = COL_BACK_FILE;
+ columns[ncolumns++] = COL_FILE_FMT_TYPE;
+ columns[ncolumns++] = COL_DIO;
+ columns[ncolumns++] = COL_LOGSEC;
+ }
+
+ if (act == A_FIND_FREE && optind < argc) {
+ /*
+ * xlosetup -f <backing_file>
+ */
+ act = A_CREATE;
+ file = argv[optind++];
+
+ if (optind < argc)
+ errx(EXIT_FAILURE, _("unexpected arguments"));
+ }
+
+ if (list && !act && optind == argc)
+ /*
+ * xlosetup --list defaults to --all
+ */
+ act = A_SHOW;
+
+ if (!act && optind + 1 == argc) {
+ /*
+ * xlosetup [--list] <device>
+ * OR
+ * xlosetup {--direct-io[=off]|--logical-blocksize=size}... <device>
+ */
+ if (!(set_dio || set_blocksize))
+ act = A_SHOW_ONE;
+ if (set_dio)
+ act = A_SET_DIRECT_IO;
+ if (set_blocksize)
+ act = A_SET_BLOCKSIZE;
+ if (!is_loopdev(argv[optind]) ||
+ loopcxt_set_device(&lc, argv[optind]))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ argv[optind]);
+ optind++;
+ }
+ if (!act) {
+ /*
+ * xlosetup <xloopdev> <backing_file>
+ */
+ act = A_CREATE;
+
+ if (optind >= argc)
+ errx(EXIT_FAILURE, _("no xloop device specified"));
+ /* don't use is_loopdev() here, the device does not have exist yet */
+ if (loopcxt_set_device(&lc, argv[optind]))
+ err(EXIT_FAILURE, _("%s: failed to use device"),
+ argv[optind]);
+ optind++;
+
+ if (optind >= argc)
+ errx(EXIT_FAILURE, _("no file specified"));
+ file = argv[optind++];
+ }
+
+ if (act != A_CREATE &&
+ (sizelimit || lo_flags || showdev || use_file_fmt_type))
+ errx(EXIT_FAILURE,
+ _("the options %s are allowed during xloop device setup only"),
+ "--{sizelimit,partscan,read-only,show,type}");
+
+ if ((flags & LOOPDEV_FL_OFFSET) &&
+ act != A_CREATE && (act != A_SHOW || !file))
+ errx(EXIT_FAILURE, _("the option --offset is not allowed in this context"));
+
+ if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
+ &ncolumns, column_name_to_id) < 0)
+ return EXIT_FAILURE;
+
+ switch (act) {
+ case A_CREATE:
+ res = create_loop(&lc, no_overlap, lo_flags, flags, file,
+ offset, sizelimit, blocksize, file_fmt_type);
+ if (res == 0) {
+ if (showdev)
+ printf("%s\n", loopcxt_get_device(&lc));
+ if (set_dio)
+ goto lo_set_dio;
+ }
+ break;
+ case A_DELETE:
+ res = delete_loop(&lc);
+ while (optind < argc) {
+ if (!is_loopdev(argv[optind]) ||
+ loopcxt_set_device(&lc, argv[optind]))
+ warn(_("%s: failed to use device"),
+ argv[optind]);
+ optind++;
+ res += delete_loop(&lc);
+ }
+ break;
+ case A_DELETE_ALL:
+ res = delete_all_loops(&lc);
+ break;
+ case A_FIND_FREE:
+ res = loopcxt_find_unused(&lc);
+ if (res) {
+ int errsv = errno;
+
+ if (access(_PATH_DEV_LOOPCTL, F_OK) == 0 &&
+ access(_PATH_DEV_LOOPCTL, W_OK) != 0)
+ ;
+ else
+ errno = errsv;
+
+ warn(_("cannot find an unused xloop device"));
+ } else
+ printf("%s\n", loopcxt_get_device(&lc));
+ break;
+ case A_SHOW:
+ if (list)
+ res = show_table(&lc, file, offset, flags);
+ else
+ res = show_all_loops(&lc, file, offset, flags);
+ break;
+ case A_SHOW_ONE:
+ if (list)
+ res = show_table(&lc, NULL, 0, 0);
+ else
+ res = printf_loopdev(&lc);
+ if (res)
+ warn("%s", loopcxt_get_device(&lc));
+ break;
+ case A_SET_CAPACITY:
+ res = loopcxt_ioctl_capacity(&lc);
+ if (res)
+ warn(_("%s: set capacity failed"),
+ loopcxt_get_device(&lc));
+ break;
+ case A_SET_DIRECT_IO:
+lo_set_dio:
+ res = loopcxt_ioctl_dio(&lc, use_dio);
+ if (res)
+ warn(_("%s: set direct io failed"),
+ loopcxt_get_device(&lc));
+ break;
+ case A_SET_BLOCKSIZE:
+ res = loopcxt_ioctl_blocksize(&lc, blocksize);
+ if (res)
+ warn(_("%s: set logical block size failed"),
+ loopcxt_get_device(&lc));
+ break;
+ default:
+ warnx(_("bad usage"));
+ errtryhelp(EXIT_FAILURE);
+ break;
+ }
+
+ loopcxt_deinit(&lc);
+ return res ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+