├── .ctags ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vimrc ├── LICENSE.GPL2 ├── LICENSE.LGPL2.1 ├── Makefile ├── README.md ├── TODO ├── conf └── netlogd.conf.in ├── doc ├── conf.py ├── index.rst └── meson.build ├── meson.build ├── meson_options.txt ├── src ├── .gitignore ├── meson.build ├── netlog │ ├── netlog-conf.c │ ├── netlog-conf.h │ ├── netlog-dtls.c │ ├── netlog-dtls.h │ ├── netlog-gperf.gperf │ ├── netlog-manager.c │ ├── netlog-manager.h │ ├── netlog-network.c │ ├── netlog-network.h │ ├── netlog-protocol.c │ ├── netlog-protocol.h │ ├── netlog-ssl.c │ ├── netlog-ssl.h │ ├── netlog-tls.c │ ├── netlog-tls.h │ └── systemd-netlogd.c └── share │ ├── alloc-util.c │ ├── alloc-util.h │ ├── build.h │ ├── capability-util.c │ ├── capability-util.h │ ├── conf-files.c │ ├── conf-files.h │ ├── conf-parser.c │ ├── conf-parser.h │ ├── def.h │ ├── dirent-util.c │ ├── dirent-util.h │ ├── dns-def.h │ ├── dns-domain.c │ ├── dns-domain.h │ ├── escape.c │ ├── escape.h │ ├── extract-word.c │ ├── extract-word.h │ ├── fd-util.c │ ├── fd-util.h │ ├── fileio.c │ ├── fileio.h │ ├── formats-util.h │ ├── fs-util.c │ ├── fs-util.h │ ├── hash-funcs.c │ ├── hash-funcs.h │ ├── hashmap.c │ ├── hashmap.h │ ├── hexdecoct.c │ ├── hexdecoct.h │ ├── hostname-util.c │ ├── hostname-util.h │ ├── in-addr-util.c │ ├── in-addr-util.h │ ├── io-util.c │ ├── io-util.h │ ├── ioprio.h │ ├── iovec-util.c │ ├── iovec-util.h │ ├── list.h │ ├── log.c │ ├── log.h │ ├── macro.h │ ├── mempool.c │ ├── mempool.h │ ├── missing.h │ ├── missing_syscall.h │ ├── mkdir.c │ ├── mkdir.h │ ├── network-util.c │ ├── network-util.h │ ├── openssl-util.h │ ├── parse-util.c │ ├── parse-util.h │ ├── path-util.c │ ├── path-util.h │ ├── proc-cmdline.c │ ├── proc-cmdline.h │ ├── process-util.c │ ├── process-util.h │ ├── random-util.c │ ├── random-util.h │ ├── ratelimit.c │ ├── ratelimit.h │ ├── sd-network.c │ ├── sd-network.h │ ├── sd-resolve.c │ ├── sd-resolve.h │ ├── set.h │ ├── signal-util.c │ ├── signal-util.h │ ├── siphash24.c │ ├── siphash24.h │ ├── socket-util.c │ ├── socket-util.h │ ├── sparse-endian.h │ ├── stat-util.c │ ├── stat-util.h │ ├── stdio-util.h │ ├── string-table.c │ ├── string-table.h │ ├── string-util.c │ ├── string-util.h │ ├── strv.c │ ├── strv.h │ ├── syslog-util.c │ ├── syslog-util.h │ ├── terminal-util.c │ ├── terminal-util.h │ ├── time-util.c │ ├── time-util.h │ ├── umask-util.h │ ├── unaligned.h │ ├── user-util.c │ ├── user-util.h │ ├── utf8.c │ ├── utf8.h │ ├── util.c │ ├── util.h │ ├── virt.c │ └── virt.h ├── systemd-netlogd.spec └── units ├── .gitignore ├── meson.build └── systemd-netlogd.service.in /.ctags: -------------------------------------------------------------------------------- 1 | --links=no 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig configuration for systemd 2 | # http://EditorConfig.org 3 | 4 | # NOTE: If you update this file make sure to update .dir-locals.el and .vimrc, 5 | # too. 6 | 7 | # Top-most EditorConfig file 8 | root = true 9 | 10 | # Unix-style newlines with a newline ending every file, utf-8 charset 11 | [*] 12 | end_of_line = lf 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | charset = utf-8 16 | 17 | [NEWS] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Match config files, set indent to spaces with width of eight 22 | [*.{c,h}] 23 | indent_style = space 24 | indent_size = 8 25 | max_line_length = 109 26 | 27 | [*.sh,mkosi.build,mkosi.prepare,mkosi.postinst] 28 | indent_style = space 29 | indent_size = 4 30 | 31 | [meson.build] 32 | indent_style = space 33 | indent_size = 8 34 | 35 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.[ch] whitespace=tab-in-indent,trailing-space 2 | *.gpg binary generated 3 | *.bmp binary 4 | *.base64 generated 5 | 6 | # Mark files as "generated", i.e. no license applies to them. 7 | # This includes output from programs, directive lists generated by grepping 8 | # for all possibilities, samples from fuzzers, files from /proc, packet samples, 9 | # and anything else where no copyright can be asserted. 10 | # 11 | # Use 'git check-attr generated -- ' to query the attribute. 12 | [attr]generated 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: systemd-netlogd CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: update 17 | run: sudo apt-get update 18 | - name: install build essentials 19 | run: sudo apt-get install -y python3-sphinx ninja-build meson glib-2.0-dev libudev-dev libsystemd-dev clang gperf libcap-dev build-essential 20 | - name: build 21 | run: make 22 | - name: install 23 | run: sudo make install 24 | - name: add systemd-journal-netlog user 25 | run: sudo useradd -r -d / -s /usr/sbin/nologin -g systemd-journal systemd-journal-netlog 26 | - name: start systemd-netlogd 27 | run: sudo systemctl daemon-reload; sudo systemctl start systemd-netlogd 28 | - name: show status systemd-netlogd 29 | run: sudo systemctl status systemd-netlogd 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.cache 2 | *.plist 3 | *.py[co] 4 | *.swp 5 | *.trs 6 | *~ 7 | .config.args 8 | .gdb_history 9 | .deps/ 10 | .mypy_cache/ 11 | __pycache__/ 12 | /*.gcda 13 | /*.gcno 14 | /*.tar.bz2 15 | /*.tar.gz 16 | /*.tar.xz 17 | /GPATH 18 | /GRTAGS 19 | /GSYMS 20 | /GTAGS 21 | /TAGS 22 | /ID 23 | /build* 24 | /coverage/ 25 | /image.raw 26 | /.#image.raw.lck 27 | /image.raw.cache-pre-dev 28 | /image.raw.cache-pre-inst 29 | /image.raw.manifest 30 | /install-tree 31 | /.mkosi-* 32 | /mkosi.builddir/ 33 | /mkosi.output/ 34 | /mkosi.installdir/ 35 | /mkosi.key 36 | /mkosi.crt 37 | mkosi.local.conf 38 | /tags 39 | .dir-locals-2.el 40 | .vscode/ 41 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | " 'set exrc' in ~/.vimrc will read .vimrc from the current directory 2 | " Warning: Enabling exrc is dangerous! You can do nearly everything from a 3 | " vimrc configuration file, including write operations and shell execution. 4 | " You should consider setting 'set secure' as well, which is highly 5 | " recommended! 6 | 7 | " Note that we set a line width of 109 for .c and XML files, but for everything 8 | " else (such as journal catalog files, unit files, README files) we stick to a 9 | " more conservative 79 characters. 10 | 11 | " NOTE: If you update this file make sure to update .dir-locals.el and 12 | " .editorconfig, too. 13 | 14 | set tabstop=8 15 | set shiftwidth=8 16 | set expandtab 17 | set makeprg=GCC_COLORS=\ make 18 | set tw=79 19 | au BufRead,BufNewFile *.xml set tw=109 shiftwidth=2 smarttab 20 | au FileType sh set tw=109 shiftwidth=4 smarttab 21 | au FileType c set tw=109 shiftwidth=8 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | ninja -C build 3 | .PHONY: all 4 | 5 | build: 6 | meson setup build 7 | 8 | clean: 9 | rm -rf build/ 10 | .PHONY: clean 11 | 12 | install: build 13 | ninja -C build install 14 | .PHONY: install 15 | 16 | format: 17 | @for f in lib/*.[ch] tool/*.[ch]; do \ 18 | echo $$f; \ 19 | astyle --quiet --options=.astylerc $$f; \ 20 | done 21 | .PHONY: format 22 | 23 | install-tree: build 24 | rm -rf build/install-tree 25 | DESTDIR=install-tree ninja -C build install 26 | tree build/install-tree 27 | .PHONY: install-tree 28 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - remove unused code 2 | -------------------------------------------------------------------------------- /conf/netlogd.conf.in: -------------------------------------------------------------------------------- 1 | [Network] 2 | #Address=239.0.0.1:6000 3 | #Protocol=udp 4 | #TLSCertificateAuthMode=deny 5 | #TLSServerCertificate= 6 | #LogFormat=rfc5424 7 | #Directory= 8 | #Namespace= 9 | #StructuredData= 10 | #UseSysLogStructuredData=no 11 | #UseSysLogMsgId=no 12 | #ConnectionRetrySec=30s 13 | #KeepAlive= 14 | #KeepAliveTimeSec= 15 | #KeepAliveIntervalSec= 16 | #KeepAliveProbes= 17 | #NoDelay=no 18 | #SendBuffer= 19 | #ExcludeSyslogFacility= 20 | #ExcludeSyslogLevel= 21 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # systemd-netlogd documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Oct 28 19:20:43 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = ['sphinx.ext.todo'] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # The suffix(es) of source filenames. 39 | # You can specify multiple suffix as a list of string: 40 | # 41 | # source_suffix = ['.rst', '.md'] 42 | source_suffix = '.rst' 43 | 44 | # The master toctree document. 45 | master_doc = 'index' 46 | 47 | # General information about the project. 48 | project = u'systemd-netlogd' 49 | copyright = u'2024, Susant Sahani' 50 | author = u'Susant Sahani ' 51 | 52 | # The version info for the project you're documenting, acts as replacement for 53 | # |version| and |release|, also used in various other places throughout the 54 | # built documents. 55 | # 56 | # The short X.Y version. 57 | version = u'1.4' 58 | # The full version, including alpha/beta/rc tags. 59 | release = u'1.4' 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | # 64 | # This is also used if you do content translation via gettext catalogs. 65 | # Usually you set "language" from the command line for these cases. 66 | language = 'en' 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | # This patterns also effect to html_static_path and html_extra_path 71 | exclude_patterns = [] 72 | 73 | # The name of the Pygments (syntax highlighting) style to use. 74 | pygments_style = 'sphinx' 75 | 76 | # If true, `todo` and `todoList` produce output, else they produce nothing. 77 | todo_include_todos = False 78 | 79 | 80 | # -- Options for HTML output ---------------------------------------------- 81 | 82 | # The theme to use for HTML and HTML Help pages. See the documentation for 83 | # a list of builtin themes. 84 | # 85 | html_theme = 'alabaster' 86 | 87 | # Theme options are theme-specific and customize the look and feel of a theme 88 | # further. For a list of options available for each theme, see the 89 | # documentation. 90 | # 91 | # html_theme_options = {} 92 | 93 | # Add any paths that contain custom static files (such as style sheets) here, 94 | # relative to this directory. They are copied after the builtin static files, 95 | # so a file named "default.css" will overwrite the builtin "default.css". 96 | html_static_path = ['_static'] 97 | 98 | 99 | # -- Options for HTMLHelp output ------------------------------------------ 100 | 101 | # Output file base name for HTML help builder. 102 | htmlhelp_basename = 'systemd-netlogddoc' 103 | 104 | # -- Options for manual page output --------------------------------------- 105 | 106 | # One entry per manual page. List of tuples 107 | # (source start file, name, description, authors, manual section). 108 | man_pages = [ 109 | (master_doc, 'systemd-netlogd', u'systemd-netlogd Documentation', 110 | [author], 8) 111 | ] 112 | -------------------------------------------------------------------------------- /doc/meson.build: -------------------------------------------------------------------------------- 1 | sphinx_sources = [ 2 | 'conf.py', 3 | 'index.rst'] 4 | 5 | man_pages = [ 6 | 'systemd-netlogd.8'] 7 | 8 | mandir1 = join_paths(get_option('mandir'), 'man1') 9 | 10 | sphinx_build = find_program('sphinx-build-3', 'sphinx-build') 11 | 12 | custom_target( 13 | 'man', 14 | command : [sphinx_build, 15 | '-b', 'man', 16 | meson.current_source_dir(), 17 | meson.current_build_dir()], 18 | input : sphinx_sources, 19 | output : man_pages, 20 | install : true, 21 | install_dir : '/usr/share/man/man8') 22 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('version-tag', type : 'string', 2 | description : 'override the git version string') 3 | 4 | option('openssl', type : 'boolean', value : true, 5 | description : 'enable openssl support') 6 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | /netlog-gperf.c 2 | /systemd-netlogd.conf 3 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | 2 | libshared_sources = files(''' 3 | share/missing_syscall.h 4 | share/missing.h 5 | share/def.h 6 | share/capability-util.c 7 | share/capability-util.h 8 | share/conf-parser.c 9 | share/conf-parser.h 10 | share/conf-files.c 11 | share/conf-files.h 12 | share/dns-def.h 13 | share/dns-domain.c 14 | share/dns-domain.h 15 | share/hostname-util.c 16 | share/hostname-util.h 17 | share/alloc-util.c 18 | share/alloc-util.h 19 | share/build.h 20 | share/set.h 21 | share/hashmap.c 22 | share/hashmap.h 23 | share/siphash24.c 24 | share/siphash24.h 25 | share/utf8.c 26 | share/utf8.h 27 | share/strv.c 28 | share/strv.h 29 | share/network-util.c 30 | share/network-util.h 31 | share/in-addr-util.c 32 | share/in-addr-util.h 33 | share/extract-word.c 34 | share/extract-word.h 35 | share/util.c 36 | share/util.h 37 | share/log.c 38 | share/log.h 39 | share/macro.h 40 | share/signal-util.c 41 | share/signal-util.h 42 | share/syslog-util.c 43 | share/syslog-util.h 44 | share/time-util.c 45 | share/time-util.h 46 | share/ioprio.h 47 | share/io-util.c 48 | share/io-util.h 49 | share/iovec-util.c 50 | share/iovec-util.h 51 | share/escape.c 52 | share/escape.h 53 | share/user-util.c 54 | share/user-util.h 55 | share/process-util.c 56 | share/process-util.h 57 | share/terminal-util.c 58 | share/terminal-util.h 59 | share/proc-cmdline.c 60 | share/proc-cmdline.h 61 | share/socket-util.c 62 | share/socket-util.h 63 | share/dirent-util.c 64 | share/dirent-util.h 65 | share/fd-util.c 66 | share/fd-util.h 67 | share/sparse-endian.h 68 | share/fileio.c 69 | share/fileio.h 70 | share/formats-util.h 71 | share/hash-funcs.c 72 | share/hash-funcs.h 73 | share/hexdecoct.c 74 | share/hexdecoct.h 75 | share/list.h 76 | share/mempool.c 77 | share/mempool.h 78 | share/parse-util.c 79 | share/parse-util.h 80 | share/path-util.c 81 | share/path-util.h 82 | share/random-util.c 83 | share/random-util.h 84 | share/ratelimit.c 85 | share/ratelimit.h 86 | share/stdio-util.h 87 | share/openssl-util.h 88 | share/string-table.c 89 | share/string-table.h 90 | share/string-util.c 91 | share/string-util.h 92 | share/unaligned.h 93 | share/stat-util.c 94 | share/stat-util.h 95 | share/fs-util.c 96 | share/fs-util.h 97 | share/mkdir.c 98 | share/mkdir.h 99 | share/virt.c 100 | share/virt.h 101 | share/sd-network.h 102 | share/sd-network.c 103 | share/sd-resolve.h 104 | share/sd-resolve.c 105 | '''.split()) 106 | 107 | libshared = static_library( 108 | 'shared', 109 | libshared_sources) 110 | 111 | systemd_netlogd_sources = files(''' 112 | netlog/systemd-netlogd.c 113 | netlog/netlog-conf.h 114 | netlog/netlog-conf.c 115 | netlog/netlog-manager.c 116 | netlog/netlog-manager.h 117 | netlog/netlog-network.c 118 | netlog/netlog-network.h 119 | netlog/netlog-protocol.c 120 | netlog/netlog-protocol.h 121 | netlog/netlog-dtls.c 122 | netlog/netlog-dtls.h 123 | netlog/netlog-ssl.c 124 | netlog/netlog-ssl.h 125 | netlog/netlog-tls.c 126 | netlog/netlog-tls.h 127 | '''.split()) 128 | 129 | netlogd_gperf_c = custom_target( 130 | 'netlog-gperf.c', 131 | input : 'netlog/netlog-gperf.gperf', 132 | output : 'netlog-gperf.c', 133 | command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) 134 | 135 | systemd_netlogd_sources += [netlogd_gperf_c] 136 | -------------------------------------------------------------------------------- /src/netlog/netlog-conf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "in-addr-util.h" 6 | #include "conf-parser.h" 7 | #include "netlog-manager.h" 8 | 9 | const struct ConfigPerfItem* netlog_gperf_lookup(const char *key, size_t length); 10 | int config_parse_netlog_remote_address(const char *unit, 11 | const char *filename, 12 | unsigned line, 13 | const char *section, 14 | unsigned section_line, 15 | const char *lvalue, 16 | int ltype, 17 | const char *rvalue, 18 | void *data, 19 | void *userdata); 20 | 21 | int config_parse_protocol(const char *unit, 22 | const char *filename, 23 | unsigned line, 24 | const char *section, 25 | unsigned section_line, 26 | const char *lvalue, 27 | int ltype, 28 | const char *rvalue, 29 | void *data, 30 | void *userdata); 31 | 32 | int config_parse_log_format(const char *unit, 33 | const char *filename, 34 | unsigned line, 35 | const char *section, 36 | unsigned section_line, 37 | const char *lvalue, 38 | int ltype, 39 | const char *rvalue, 40 | void *data, 41 | void *userdata); 42 | 43 | int config_parse_tls_certificate_auth_mode(const char *unit, 44 | const char *filename, 45 | unsigned line, 46 | const char *section, 47 | unsigned section_line, 48 | const char *lvalue, 49 | int ltype, 50 | const char *rvalue, 51 | void *data, 52 | void *userdata); 53 | 54 | int config_parse_namespace(const char *unit, 55 | const char *filename, 56 | unsigned line, 57 | const char *section, 58 | unsigned section_line, 59 | const char *lvalue, 60 | int ltype, 61 | const char *rvalue, 62 | void *data, 63 | void *userdata); 64 | 65 | int config_parse_syslog_facility(const char *unit, 66 | const char *filename, 67 | unsigned line, 68 | const char *section, 69 | unsigned section_line, 70 | const char *lvalue, 71 | int ltype, 72 | const char *rvalue, 73 | void *data, 74 | void *userdata); 75 | 76 | int config_parse_syslog_level(const char *unit, 77 | const char *filename, 78 | unsigned line, 79 | const char *section, 80 | unsigned section_line, 81 | const char *lvalue, 82 | int ltype, 83 | const char *rvalue, 84 | void *data, 85 | void *userdata); 86 | 87 | int manager_parse_config_file(Manager *m); 88 | -------------------------------------------------------------------------------- /src/netlog/netlog-dtls.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "socket-util.h" 8 | #include "openssl-util.h" 9 | #include "netlog-tls.h" 10 | 11 | typedef struct DTLSManager DTLSManager; 12 | 13 | struct DTLSManager { 14 | SSL_CTX *ctx; 15 | SSL *ssl; 16 | 17 | char *pretty_address; 18 | int fd; 19 | bool connected; 20 | 21 | OpenSSLCertificateAuthMode auth_mode; 22 | }; 23 | 24 | void dtls_manager_free(DTLSManager *m); 25 | int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, const char *server_cert, DTLSManager **ret); 26 | 27 | int dtls_connect(DTLSManager *m, SocketAddress *addr); 28 | void dtls_disconnect(DTLSManager *m); 29 | 30 | int dtls_datagram_writev(DTLSManager *m, const struct iovec *iov, size_t iovcnt); 31 | 32 | DEFINE_TRIVIAL_CLEANUP_FUNC(DTLSManager*, dtls_manager_free); 33 | -------------------------------------------------------------------------------- /src/netlog/netlog-gperf.gperf: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "conf-parser.h" 4 | #include "netlog-conf.h" 5 | #include "netlog-manager.h" 6 | %} 7 | struct ConfigPerfItem; 8 | %null_strings 9 | %language=ANSI-C 10 | %define slot-name section_and_lvalue 11 | %define hash-function-name netlog_gperf_hash 12 | %define lookup-function-name netlog_gperf_lookup 13 | %readonly-tables 14 | %omit-struct-type 15 | %struct-type 16 | %includes 17 | %% 18 | Network.Address, config_parse_netlog_remote_address, 0, 0 19 | Network.Protocol, config_parse_protocol, 0, offsetof(Manager, protocol) 20 | Network.LogFormat, config_parse_log_format, 0, offsetof(Manager, log_format) 21 | Network.Directory, config_parse_string, 0, offsetof(Manager, dir) 22 | Network.Namespace, config_parse_namespace, 0, offsetof(Manager, namespace) 23 | Network.StructuredData, config_parse_string, 0, offsetof(Manager, structured_data) 24 | Network.UseSysLogStructuredData, config_parse_bool, 0, offsetof(Manager, syslog_structured_data) 25 | Network.UseSysLogMsgId, config_parse_bool, 0, offsetof(Manager, syslog_msgid) 26 | Network.ConnectionRetrySec, config_parse_sec, 0, offsetof(Manager, connection_retry_usec) 27 | Network.TLSCertificateAuthMode, config_parse_tls_certificate_auth_mode, 0, offsetof(Manager, auth_mode) 28 | Network.TLSServerCertificate, config_parse_string, 0, offsetof(Manager, server_cert) 29 | Network.KeepAlive, config_parse_bool, 0, offsetof(Manager, keep_alive) 30 | Network.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Manager, keep_alive_time) 31 | Network.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Manager, keep_alive_interval) 32 | Network.KeepAliveProbes, config_parse_unsigned, 0, offsetof(Manager, keep_alive_cnt) 33 | Network.NoDelay, config_parse_bool, 0, offsetof(Manager, no_delay) 34 | Network.SendBuffer, config_parse_iec_size, 0, offsetof(Manager, send_buffer) 35 | Network.ExcludeSyslogFacility, config_parse_syslog_facility, 0, offsetof(Manager, excluded_syslog_facilities) 36 | Network.ExcludeSyslogLevel, config_parse_syslog_level, 0, offsetof(Manager, excluded_syslog_levels) 37 | -------------------------------------------------------------------------------- /src/netlog/netlog-network.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "netlog-manager.h" 6 | 7 | int network_send(Manager *m, struct iovec *iovec, unsigned n_iovec); 8 | -------------------------------------------------------------------------------- /src/netlog/netlog-protocol.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "netlog-manager.h" 6 | 7 | int protocol_send(Manager *m, struct iovec *iovec, unsigned n_iovec); 8 | void format_rfc3339_timestamp(const struct timeval *tv, char *header_time, size_t header_size); 9 | int format_rfc5424(Manager *m, int severity, int facility, const char *identifier, const char *message, const char *hostname, 10 | const char *pid, const struct timeval *tv, const char *syslog_structured_data, const char *syslog_msgid); 11 | int format_rfc3339(Manager *m, int severity, int facility, const char *identifier, const char *message, const char *hostname, 12 | const char *pid, const struct timeval *tv); 13 | -------------------------------------------------------------------------------- /src/netlog/netlog-ssl.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include "netlog-ssl.h" 4 | 5 | #include "alloc-util.h" 6 | #include "openssl-util.h" 7 | #include "socket-util.h" 8 | 9 | #include "netlog-dtls.h" 10 | #include "netlog-tls.h" 11 | 12 | static_assert(offsetof(TLSManager, auth_mode) == offsetof(DTLSManager, auth_mode), "TLSManager and DTLSManager must be similar"); 13 | 14 | /* inspired by SSL_set_verify(3) */ 15 | int ssl_verify_certificate_validity(int preverify_ok, X509_STORE_CTX *store) { 16 | const SSL* ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); 17 | const char *pretty = (const char *) SSL_get_ex_data(ssl, EX_DATA_PRETTYADDRESS); 18 | const TLSManager *m = (const TLSManager *) SSL_get_ex_data(ssl, EX_DATA_TLSMANAGER); 19 | const X509 *error_cert = X509_STORE_CTX_get_current_cert(store); 20 | int depth = X509_STORE_CTX_get_error_depth(store); 21 | int error = X509_STORE_CTX_get_error(store); 22 | char subject_buf[256]; 23 | char issuer_buf[256]; 24 | int log_level; 25 | 26 | assert(store); 27 | assert(pretty); 28 | assert(m); 29 | 30 | X509_NAME_oneline(X509_get_subject_name(error_cert), subject_buf, sizeof(subject_buf)); 31 | X509_NAME_oneline(X509_get_issuer_name(error_cert), issuer_buf, sizeof(issuer_buf)); 32 | 33 | log_debug("TLS: Verifying SSL certificates of server %s: certificate: subject='%s' issuer='%s' depth=%d preverify_ok=%d error=%d/%s ...", 34 | pretty, subject_buf, issuer_buf, depth, preverify_ok, error, X509_verify_cert_error_string(error)); 35 | 36 | if (depth > VERIFICATION_DEPTH) { 37 | /* 38 | * From man:SSL_set_verif(3): 39 | * 40 | * Catch a too long certificate chain. The depth limit set using 41 | * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so 42 | * that whenever the "depth>verify_depth" condition is met, we 43 | * have violated the limit and want to log this error condition. 44 | * We must do it here, because the CHAIN_TOO_LONG error would not 45 | * be found explicitly; only errors introduced by cutting off the 46 | * additional certificates would be logged. 47 | */ 48 | preverify_ok = 0; 49 | error = X509_V_ERR_CERT_CHAIN_TOO_LONG; 50 | X509_STORE_CTX_set_error(store, error); 51 | } 52 | 53 | if (preverify_ok) { 54 | log_debug("TLS: Verified SSL certificate of server=%s (certificate: subject='%s' issuer='%s' depth=%d): %s", 55 | pretty, subject_buf, issuer_buf, depth, X509_verify_cert_error_string(error)); 56 | return preverify_ok; 57 | } 58 | 59 | switch (m->auth_mode) { 60 | case OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY: 61 | log_level = LOG_ERR; 62 | break; 63 | case OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN: 64 | log_level = LOG_WARNING; 65 | preverify_ok = 1; 66 | break; 67 | case OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW: 68 | log_level = LOG_DEBUG; 69 | preverify_ok = 1; 70 | break; 71 | default: 72 | assert_not_reached("Invalid certificate authentication mode"); /* mode NO does not set this callback */ 73 | } 74 | 75 | log_full(log_level, "TLS: Failed to verify certificate of server=%s (certificate: subject='%s' issuer='%s' depth=%d)%s: %s", 76 | pretty, subject_buf, issuer_buf, depth, 77 | preverify_ok ? ", ignoring" : "", 78 | X509_verify_cert_error_string(error)); 79 | 80 | return preverify_ok; 81 | } 82 | -------------------------------------------------------------------------------- /src/netlog/netlog-ssl.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "macro.h" 7 | 8 | #define VERIFICATION_DEPTH 20 9 | 10 | #define EX_DATA_TLSMANAGER 0 11 | #define EX_DATA_PRETTYADDRESS 1 12 | 13 | int ssl_verify_certificate_validity(int preverify_ok, X509_STORE_CTX *store); 14 | 15 | DEFINE_TRIVIAL_CLEANUP_FUNC(SSL_CTX*, SSL_CTX_free); 16 | -------------------------------------------------------------------------------- /src/netlog/netlog-tls.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "socket-util.h" 8 | #include "openssl-util.h" 9 | 10 | typedef enum OpenSSLCertificateAuthMode { 11 | OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE = 0, 12 | OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW = 1, 13 | OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY = 2, 14 | OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN = 3, 15 | _OPEN_SSL_CERTIFICATE_AUTH_MODE_MAX, 16 | _OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID = -EINVAL, 17 | } OpenSSLCertificateAuthMode; 18 | 19 | typedef struct TLSManager TLSManager; 20 | 21 | struct TLSManager { 22 | SSL_CTX *ctx; 23 | SSL *ssl; 24 | 25 | char *pretty_address; 26 | int fd; 27 | 28 | bool connected; 29 | OpenSSLCertificateAuthMode auth_mode; 30 | }; 31 | 32 | void tls_manager_free(TLSManager *m); 33 | int tls_manager_init(OpenSSLCertificateAuthMode auth, const char *server_cert, TLSManager **ret); 34 | 35 | int tls_connect(TLSManager *m, SocketAddress *addr); 36 | void tls_disconnect(TLSManager *m); 37 | 38 | int tls_stream_writev(TLSManager *m, const struct iovec *iov, size_t iovcnt); 39 | 40 | const char *certificate_auth_mode_to_string(OpenSSLCertificateAuthMode v) _const_; 41 | OpenSSLCertificateAuthMode certificate_auth_mode_from_string(const char *s) _pure_; 42 | 43 | 44 | DEFINE_TRIVIAL_CLEANUP_FUNC(TLSManager*, tls_manager_free); 45 | -------------------------------------------------------------------------------- /src/share/alloc-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | 6 | #include "alloc-util.h" 7 | #include "macro.h" 8 | #include "util.h" 9 | 10 | void* memdup(const void *p, size_t l) { 11 | void *r; 12 | 13 | assert(p); 14 | 15 | r = malloc(l); 16 | if (!r) 17 | return NULL; 18 | 19 | memcpy(r, p, l); 20 | return r; 21 | } 22 | 23 | void* memdup_suffix0(const void *p, size_t l) { 24 | void *ret; 25 | 26 | assert(l == 0 || p); 27 | 28 | /* The same as memdup() but place a safety NUL byte after the allocated memory */ 29 | 30 | if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */ 31 | return NULL; 32 | 33 | ret = malloc(l + 1); 34 | if (!ret) 35 | return NULL; 36 | 37 | ((uint8_t*) ret)[l] = 0; 38 | return memcpy_safe(ret, p, l); 39 | } 40 | 41 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { 42 | size_t a, newalloc; 43 | void *q; 44 | 45 | assert(p); 46 | assert(allocated); 47 | 48 | if (*allocated >= need) 49 | return *p; 50 | 51 | newalloc = MAX(need * 2, 64u / size); 52 | a = newalloc * size; 53 | 54 | /* check for overflows */ 55 | if (a < size * need) 56 | return NULL; 57 | 58 | q = realloc(*p, a); 59 | if (!q) 60 | return NULL; 61 | 62 | *p = q; 63 | *allocated = newalloc; 64 | return q; 65 | } 66 | 67 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { 68 | size_t prev; 69 | uint8_t *q; 70 | 71 | assert(p); 72 | assert(allocated); 73 | 74 | prev = *allocated; 75 | 76 | q = greedy_realloc(p, allocated, need, size); 77 | if (!q) 78 | return NULL; 79 | 80 | if (*allocated > prev) 81 | memzero(q + prev * size, (*allocated - prev) * size); 82 | 83 | return q; 84 | } 85 | -------------------------------------------------------------------------------- /src/share/alloc-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "macro.h" 10 | 11 | /* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */ 12 | static inline void *memcpy_safe(void *dst, const void *src, size_t n) { 13 | if (n == 0) 14 | return dst; 15 | assert(src); 16 | return memcpy(dst, src, n); 17 | } 18 | 19 | /* Normal mempcpy() requires src to be nonnull. We do nothing if n is 0. */ 20 | static inline void *mempcpy_safe(void *dst, const void *src, size_t n) { 21 | if (n == 0) 22 | return dst; 23 | assert(src); 24 | return mempcpy(dst, src, n); 25 | } 26 | 27 | /* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */ 28 | static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { 29 | if (n == 0) 30 | return 0; 31 | assert(s1); 32 | assert(s2); 33 | return memcmp(s1, s2, n); 34 | } 35 | 36 | #define zero(x) (memzero(&(x), sizeof(x))) 37 | 38 | #define new(t, n) ((t*) malloc_multiply(n, sizeof(t))) 39 | 40 | #define new0(t, n) ((t*) calloc((n), sizeof(t))) 41 | 42 | #define newa(t, n) ((t*) alloca(sizeof(t)*(n))) 43 | 44 | #define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) 45 | 46 | #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) 47 | 48 | #define malloc0(n) (calloc(1, (n))) 49 | 50 | static inline void *mfree(void *memory) { 51 | free(memory); 52 | return NULL; 53 | } 54 | 55 | static inline void freep(void *p) { 56 | free(*(void**) p); 57 | } 58 | 59 | #define _cleanup_free_ _cleanup_(freep) 60 | 61 | void* memdup(const void *p, size_t l) _alloc_(2); 62 | void* memdup_suffix0(const void *p, size_t l); 63 | 64 | #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, n, sizeof(t))) 65 | 66 | static inline bool size_multiply_overflow(size_t size, size_t need) { 67 | return _unlikely_(need != 0 && size > (SIZE_MAX / need)); 68 | } 69 | 70 | _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { 71 | if (size_multiply_overflow(size, need)) 72 | return NULL; 73 | 74 | return malloc(size * need); 75 | } 76 | 77 | _alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) { 78 | if (size_multiply_overflow(size, need)) 79 | return NULL; 80 | 81 | return realloc(p, size * need); 82 | } 83 | 84 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { 85 | if (size_multiply_overflow(size, need)) 86 | return NULL; 87 | 88 | return memdup(p, size * need); 89 | } 90 | 91 | /* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger 92 | * than the product of its parameters. */ 93 | static inline void *memdup_suffix0_multiply(const void *p, size_t need, size_t size) { 94 | if (size_multiply_overflow(size, need)) 95 | return NULL; 96 | 97 | return memdup_suffix0(p, size * need); 98 | } 99 | 100 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); 101 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); 102 | 103 | #define GREEDY_REALLOC(array, allocated, need) \ 104 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) 105 | 106 | #define GREEDY_REALLOC0(array, allocated, need) \ 107 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) 108 | 109 | #define alloca0(n) \ 110 | ({ \ 111 | char *_new_; \ 112 | size_t _len_ = n; \ 113 | _new_ = alloca(_len_); \ 114 | (void *) memset(_new_, 0, _len_); \ 115 | }) 116 | 117 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ 118 | #define alloca_align(size, align) \ 119 | ({ \ 120 | void *_ptr_; \ 121 | size_t _mask_ = (align) - 1; \ 122 | _ptr_ = alloca((size) + _mask_); \ 123 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ 124 | }) 125 | 126 | #define alloca0_align(size, align) \ 127 | ({ \ 128 | void *_new_; \ 129 | size_t _size_ = (size); \ 130 | _new_ = alloca_align(_size_, (align)); \ 131 | (void*)memset(_new_, 0, _size_); \ 132 | }) 133 | 134 | #define free_and_replace_full(a, b, free_func) \ 135 | ({ \ 136 | typeof(a)* _a = &(a); \ 137 | typeof(b)* _b = &(b); \ 138 | free_func(*_a); \ 139 | *_a = *_b; \ 140 | *_b = NULL; \ 141 | 0; \ 142 | }) 143 | 144 | #define free_and_replace(a, b) \ 145 | free_and_replace_full(a, b, free) 146 | -------------------------------------------------------------------------------- /src/share/build.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 4 | 5 | #ifdef HAVE_PAM 6 | #define _PAM_FEATURE_ "+PAM" 7 | #else 8 | #define _PAM_FEATURE_ "-PAM" 9 | #endif 10 | 11 | #ifdef HAVE_AUDIT 12 | #define _AUDIT_FEATURE_ "+AUDIT" 13 | #else 14 | #define _AUDIT_FEATURE_ "-AUDIT" 15 | #endif 16 | 17 | #ifdef HAVE_SELINUX 18 | #define _SELINUX_FEATURE_ "+SELINUX" 19 | #else 20 | #define _SELINUX_FEATURE_ "-SELINUX" 21 | #endif 22 | 23 | #ifdef HAVE_APPARMOR 24 | #define _APPARMOR_FEATURE_ "+APPARMOR" 25 | #else 26 | #define _APPARMOR_FEATURE_ "-APPARMOR" 27 | #endif 28 | 29 | #ifdef HAVE_IMA 30 | #define _IMA_FEATURE_ "+IMA" 31 | #else 32 | #define _IMA_FEATURE_ "-IMA" 33 | #endif 34 | 35 | #ifdef HAVE_SMACK 36 | #define _SMACK_FEATURE_ "+SMACK" 37 | #else 38 | #define _SMACK_FEATURE_ "-SMACK" 39 | #endif 40 | 41 | #ifdef HAVE_SYSV_COMPAT 42 | #define _SYSVINIT_FEATURE_ "+SYSVINIT" 43 | #else 44 | #define _SYSVINIT_FEATURE_ "-SYSVINIT" 45 | #endif 46 | 47 | #ifdef HAVE_UTMP 48 | #define _UTMP_FEATURE_ "+UTMP" 49 | #else 50 | #define _UTMP_FEATURE_ "-UTMP" 51 | #endif 52 | 53 | #ifdef HAVE_LIBCRYPTSETUP 54 | #define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" 55 | #else 56 | #define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" 57 | #endif 58 | 59 | #ifdef HAVE_GCRYPT 60 | #define _GCRYPT_FEATURE_ "+GCRYPT" 61 | #else 62 | #define _GCRYPT_FEATURE_ "-GCRYPT" 63 | #endif 64 | 65 | #ifdef HAVE_GNUTLS 66 | #define _GNUTLS_FEATURE_ "+GNUTLS" 67 | #else 68 | #define _GNUTLS_FEATURE_ "-GNUTLS" 69 | #endif 70 | 71 | #ifdef HAVE_ACL 72 | #define _ACL_FEATURE_ "+ACL" 73 | #else 74 | #define _ACL_FEATURE_ "-ACL" 75 | #endif 76 | 77 | #ifdef HAVE_XZ 78 | #define _XZ_FEATURE_ "+XZ" 79 | #else 80 | #define _XZ_FEATURE_ "-XZ" 81 | #endif 82 | 83 | #ifdef HAVE_LZ4 84 | #define _LZ4_FEATURE_ "+LZ4" 85 | #else 86 | #define _LZ4_FEATURE_ "-LZ4" 87 | #endif 88 | 89 | #ifdef HAVE_SECCOMP 90 | #define _SECCOMP_FEATURE_ "+SECCOMP" 91 | #else 92 | #define _SECCOMP_FEATURE_ "-SECCOMP" 93 | #endif 94 | 95 | #ifdef HAVE_BLKID 96 | #define _BLKID_FEATURE_ "+BLKID" 97 | #else 98 | #define _BLKID_FEATURE_ "-BLKID" 99 | #endif 100 | 101 | #ifdef HAVE_ELFUTILS 102 | #define _ELFUTILS_FEATURE_ "+ELFUTILS" 103 | #else 104 | #define _ELFUTILS_FEATURE_ "-ELFUTILS" 105 | #endif 106 | 107 | #ifdef HAVE_KMOD 108 | #define _KMOD_FEATURE_ "+KMOD" 109 | #else 110 | #define _KMOD_FEATURE_ "-KMOD" 111 | #endif 112 | 113 | #ifdef HAVE_LIBIDN 114 | #define _IDN_FEATURE_ "+IDN" 115 | #else 116 | #define _IDN_FEATURE_ "-IDN" 117 | #endif 118 | 119 | #define SYSTEMD_FEATURES \ 120 | _PAM_FEATURE_ " " \ 121 | _AUDIT_FEATURE_ " " \ 122 | _SELINUX_FEATURE_ " " \ 123 | _IMA_FEATURE_ " " \ 124 | _APPARMOR_FEATURE_ " " \ 125 | _SMACK_FEATURE_ " " \ 126 | _SYSVINIT_FEATURE_ " " \ 127 | _UTMP_FEATURE_ " " \ 128 | _LIBCRYPTSETUP_FEATURE_ " " \ 129 | _GCRYPT_FEATURE_ " " \ 130 | _GNUTLS_FEATURE_ " " \ 131 | _ACL_FEATURE_ " " \ 132 | _XZ_FEATURE_ " " \ 133 | _LZ4_FEATURE_ " " \ 134 | _SECCOMP_FEATURE_ " " \ 135 | _BLKID_FEATURE_ " " \ 136 | _ELFUTILS_FEATURE_ " " \ 137 | _KMOD_FEATURE_ " " \ 138 | _IDN_FEATURE_ 139 | -------------------------------------------------------------------------------- /src/share/capability-util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | #include "util.h" 12 | 13 | #define CAP_ALL (uint64_t) -1 14 | 15 | unsigned long cap_last_cap(void); 16 | int capability_bounding_set_drop(uint64_t keep, bool right_now); 17 | 18 | int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities); 19 | 20 | int drop_capability(cap_value_t cv); 21 | 22 | DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free); 23 | #define _cleanup_cap_free_ _cleanup_(cap_freep) 24 | 25 | static inline void cap_free_charpp(char **p) { 26 | if (*p) 27 | cap_free(*p); 28 | } 29 | #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp) 30 | 31 | static inline bool cap_test_all(uint64_t caps) { 32 | uint64_t m; 33 | m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1; 34 | return (caps & m) == m; 35 | } 36 | -------------------------------------------------------------------------------- /src/share/conf-files.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "conf-files.h" 11 | #include "dirent-util.h" 12 | #include "fd-util.h" 13 | #include "hashmap.h" 14 | #include "log.h" 15 | #include "macro.h" 16 | #include "missing.h" 17 | #include "path-util.h" 18 | #include "string-util.h" 19 | #include "strv.h" 20 | #include "util.h" 21 | 22 | static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { 23 | _cleanup_closedir_ DIR *dir = NULL; 24 | const char *dirpath; 25 | struct dirent *de; 26 | int r; 27 | 28 | assert(path); 29 | assert(suffix); 30 | 31 | dirpath = prefix_roota(root, path); 32 | 33 | dir = opendir(dirpath); 34 | if (!dir) { 35 | if (errno == ENOENT) 36 | return 0; 37 | return -errno; 38 | } 39 | 40 | FOREACH_DIRENT(de, dir, return -errno) { 41 | char *p; 42 | 43 | if (!dirent_is_file_with_suffix(de, suffix)) 44 | continue; 45 | 46 | p = strjoin(dirpath, "/", de->d_name, NULL); 47 | if (!p) 48 | return -ENOMEM; 49 | 50 | r = hashmap_put(h, basename(p), p); 51 | if (r == -EEXIST) { 52 | log_debug("Skipping overridden file: %s.", p); 53 | free(p); 54 | } else if (r < 0) { 55 | free(p); 56 | return r; 57 | } else if (r == 0) { 58 | log_debug("Duplicate file %s", p); 59 | free(p); 60 | } 61 | } 62 | 63 | return 0; 64 | } 65 | 66 | static int base_cmp(const void *a, const void *b) { 67 | const char *s1, *s2; 68 | 69 | s1 = *(char * const *)a; 70 | s2 = *(char * const *)b; 71 | return strcmp(basename(s1), basename(s2)); 72 | } 73 | 74 | static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) { 75 | _cleanup_hashmap_free_ Hashmap *fh = NULL; 76 | char **files, **p; 77 | int r; 78 | 79 | assert(strv); 80 | assert(suffix); 81 | 82 | /* This alters the dirs string array */ 83 | if (!path_strv_resolve_uniq(dirs, root)) 84 | return -ENOMEM; 85 | 86 | fh = hashmap_new(&string_hash_ops); 87 | if (!fh) 88 | return -ENOMEM; 89 | 90 | STRV_FOREACH(p, dirs) { 91 | r = files_add(fh, root, *p, suffix); 92 | if (r == -ENOMEM) 93 | return r; 94 | if (r < 0) 95 | log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p); 96 | } 97 | 98 | files = hashmap_get_strv(fh); 99 | if (!files) 100 | return -ENOMEM; 101 | 102 | qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); 103 | *strv = files; 104 | 105 | return 0; 106 | } 107 | 108 | int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) { 109 | _cleanup_strv_free_ char **copy = NULL; 110 | 111 | assert(strv); 112 | assert(suffix); 113 | 114 | copy = strv_copy((char**) dirs); 115 | if (!copy) 116 | return -ENOMEM; 117 | 118 | return conf_files_list_strv_internal(strv, suffix, root, copy); 119 | } 120 | 121 | int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) { 122 | _cleanup_strv_free_ char **dirs = NULL; 123 | 124 | assert(strv); 125 | assert(suffix); 126 | 127 | dirs = strv_split_nulstr(d); 128 | if (!dirs) 129 | return -ENOMEM; 130 | 131 | return conf_files_list_strv_internal(strv, suffix, root, dirs); 132 | } 133 | -------------------------------------------------------------------------------- /src/share/conf-files.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | int conf_files_list_strv(char ***ret, const char *suffix, const char *root, const char* const* dirs); 6 | int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs); 7 | -------------------------------------------------------------------------------- /src/share/def.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "util.h" 6 | 7 | #define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC) 8 | #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) 9 | #define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC) 10 | 11 | #define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC) 12 | #define DEFAULT_START_LIMIT_BURST 5 13 | 14 | /* The default time after which exit-on-idle services exit. This 15 | * should be kept lower than the watchdog timeout, because otherwise 16 | * the watchdog pings will keep the loop busy. */ 17 | #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) 18 | 19 | /* The default value for the net.unix.max_dgram_qlen sysctl */ 20 | #define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL 21 | 22 | #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" 23 | 24 | #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT 25 | #define SIGNALS_IGNORE SIGPIPE 26 | 27 | #ifdef HAVE_SPLIT_USR 28 | #define KBD_KEYMAP_DIRS \ 29 | "/usr/share/keymaps/\0" \ 30 | "/usr/share/kbd/keymaps/\0" \ 31 | "/usr/lib/kbd/keymaps/\0" \ 32 | "/lib/kbd/keymaps/\0" 33 | #else 34 | #define KBD_KEYMAP_DIRS \ 35 | "/usr/share/keymaps/\0" \ 36 | "/usr/share/kbd/keymaps/\0" \ 37 | "/usr/lib/kbd/keymaps/\0" 38 | #endif 39 | 40 | #define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" 41 | #define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus" 42 | #define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS 43 | #define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus" 44 | #define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus" 45 | 46 | #define PLYMOUTH_SOCKET { \ 47 | .un.sun_family = AF_UNIX, \ 48 | .un.sun_path = "\0/org/freedesktop/plymouthd", \ 49 | } 50 | 51 | #ifndef TTY_GID 52 | #define TTY_GID 5 53 | #endif 54 | 55 | #define NOTIFY_FD_MAX 768 56 | #define NOTIFY_BUFFER_MAX PIPE_BUF 57 | 58 | #ifdef HAVE_SPLIT_USR 59 | #define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0" 60 | #else 61 | #define _CONF_PATHS_SPLIT_USR(n) 62 | #endif 63 | 64 | /* Return a nulstr for a standard cascade of configuration paths, 65 | * suitable to pass to conf_files_list_nulstr() or config_parse_many() 66 | * to implement drop-in directories for extending configuration 67 | * files. */ 68 | #define CONF_PATHS_NULSTR(n) \ 69 | "/etc/" n "\0" \ 70 | "/run/" n "\0" \ 71 | "/usr/local/lib/" n "\0" \ 72 | "/usr/lib/" n "\0" \ 73 | _CONF_PATHS_SPLIT_USR(n) 74 | -------------------------------------------------------------------------------- /src/share/dirent-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | 6 | #include "dirent-util.h" 7 | #include "path-util.h" 8 | #include "string-util.h" 9 | 10 | bool dirent_is_file(const struct dirent *de) { 11 | assert(de); 12 | 13 | if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) 14 | return false; 15 | 16 | if (hidden_or_backup_file(de->d_name)) 17 | return false; 18 | 19 | return true; 20 | } 21 | 22 | bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { 23 | assert(de); 24 | 25 | if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) 26 | return false; 27 | 28 | if (de->d_name[0] == '.') 29 | return false; 30 | 31 | return endswith(de->d_name, suffix); 32 | } 33 | -------------------------------------------------------------------------------- /src/share/dirent-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "macro.h" 9 | #include "path-util.h" 10 | 11 | bool dirent_is_file(const struct dirent *de) _pure_; 12 | bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; 13 | 14 | #define FOREACH_DIRENT(de, d, on_error) \ 15 | for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ 16 | if (!de) { \ 17 | if (errno > 0) { \ 18 | on_error; \ 19 | } \ 20 | break; \ 21 | } else if (hidden_or_backup_file((de)->d_name)) \ 22 | continue; \ 23 | else 24 | 25 | #define FOREACH_DIRENT_ALL(de, d, on_error) \ 26 | for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ 27 | if (!de) { \ 28 | if (errno > 0) { \ 29 | on_error; \ 30 | } \ 31 | break; \ 32 | } else 33 | -------------------------------------------------------------------------------- /src/share/dns-def.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | /* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ 5 | #define DNS_LABEL_MAX 63 6 | 7 | /* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ 8 | #define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) 9 | 10 | /* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ 11 | #define DNS_HOSTNAME_MAX 253 12 | 13 | /* Maximum length of a full hostname, on the wire, including the final NUL byte */ 14 | #define DNS_WIRE_FORMAT_HOSTNAME_MAX 255 15 | 16 | /* Maximum number of labels per valid hostname */ 17 | #define DNS_N_LABELS_MAX 127 18 | -------------------------------------------------------------------------------- /src/share/dns-domain.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "dns-def.h" 10 | #include "hashmap.h" 11 | #include "in-addr-util.h" 12 | 13 | typedef enum DNSLabelFlags { 14 | DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */ 15 | DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */ 16 | DNS_LABEL_LEAVE_TRAILING_DOT = 1 << 2, /* Leave trailing dot in place */ 17 | } DNSLabelFlags; 18 | 19 | int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret); 20 | 21 | static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) { 22 | /* dns_name_concat() normalizes as a side-effect */ 23 | return dns_name_concat(s, NULL, flags, ret); 24 | } 25 | 26 | static inline int dns_name_is_valid(const char *s) { 27 | int r; 28 | 29 | /* dns_name_concat() verifies as a side effect */ 30 | r = dns_name_concat(s, NULL, 0, NULL); 31 | if (r == -EINVAL) 32 | return 0; 33 | if (r < 0) 34 | return r; 35 | return 1; 36 | } 37 | 38 | int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags); 39 | int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); 40 | int dns_name_address(const char *p, int *family, union in_addr_union *a); 41 | int dns_name_is_valid_or_address(const char *name); 42 | -------------------------------------------------------------------------------- /src/share/escape.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alloc-util.h" 8 | #include "escape.h" 9 | #include "hexdecoct.h" 10 | #include "macro.h" 11 | #include "utf8.h" 12 | 13 | int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) { 14 | int r = 1; 15 | 16 | assert(p); 17 | assert(*p); 18 | assert(ret); 19 | 20 | /* Unescapes C style. Returns the unescaped character in ret. 21 | * Sets *eight_bit to true if the escaped sequence either fits in 22 | * one byte in UTF-8 or is a non-unicode literal byte and should 23 | * instead be copied directly. 24 | */ 25 | 26 | if (length != (size_t) -1 && length < 1) 27 | return -EINVAL; 28 | 29 | switch (p[0]) { 30 | 31 | case 'a': 32 | *ret = '\a'; 33 | break; 34 | case 'b': 35 | *ret = '\b'; 36 | break; 37 | case 'f': 38 | *ret = '\f'; 39 | break; 40 | case 'n': 41 | *ret = '\n'; 42 | break; 43 | case 'r': 44 | *ret = '\r'; 45 | break; 46 | case 't': 47 | *ret = '\t'; 48 | break; 49 | case 'v': 50 | *ret = '\v'; 51 | break; 52 | case '\\': 53 | *ret = '\\'; 54 | break; 55 | case '"': 56 | *ret = '"'; 57 | break; 58 | case '\'': 59 | *ret = '\''; 60 | break; 61 | 62 | case 's': 63 | /* This is an extension of the XDG syntax files */ 64 | *ret = ' '; 65 | break; 66 | 67 | case 'x': { 68 | /* hexadecimal encoding */ 69 | int a, b; 70 | 71 | if (length != (size_t) -1 && length < 3) 72 | return -EINVAL; 73 | 74 | a = unhexchar(p[1]); 75 | if (a < 0) 76 | return -EINVAL; 77 | 78 | b = unhexchar(p[2]); 79 | if (b < 0) 80 | return -EINVAL; 81 | 82 | /* Don't allow NUL bytes */ 83 | if (a == 0 && b == 0) 84 | return -EINVAL; 85 | 86 | *ret = (a << 4U) | b; 87 | *eight_bit = true; 88 | r = 3; 89 | break; 90 | } 91 | 92 | case 'u': { 93 | /* C++11 style 16bit unicode */ 94 | 95 | int a[4]; 96 | unsigned i; 97 | uint32_t c; 98 | 99 | if (length != (size_t) -1 && length < 5) 100 | return -EINVAL; 101 | 102 | for (i = 0; i < 4; i++) { 103 | a[i] = unhexchar(p[1 + i]); 104 | if (a[i] < 0) 105 | return a[i]; 106 | } 107 | 108 | c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; 109 | 110 | /* Don't allow 0 chars */ 111 | if (c == 0) 112 | return -EINVAL; 113 | 114 | *ret = c; 115 | r = 5; 116 | break; 117 | } 118 | 119 | case 'U': { 120 | /* C++11 style 32bit unicode */ 121 | 122 | int a[8]; 123 | unsigned i; 124 | char32_t c; 125 | 126 | if (length != (size_t) -1 && length < 9) 127 | return -EINVAL; 128 | 129 | for (i = 0; i < 8; i++) { 130 | a[i] = unhexchar(p[1 + i]); 131 | if (a[i] < 0) 132 | return a[i]; 133 | } 134 | 135 | c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | 136 | ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; 137 | 138 | /* Don't allow 0 chars */ 139 | if (c == 0) 140 | return -EINVAL; 141 | 142 | /* Don't allow invalid code points */ 143 | if (!unichar_is_valid(c)) 144 | return -EINVAL; 145 | 146 | *ret = c; 147 | r = 9; 148 | break; 149 | } 150 | 151 | case '0': 152 | case '1': 153 | case '2': 154 | case '3': 155 | case '4': 156 | case '5': 157 | case '6': 158 | case '7': { 159 | /* octal encoding */ 160 | int a, b, c; 161 | char32_t m; 162 | 163 | if (length != (size_t) -1 && length < 3) 164 | return -EINVAL; 165 | 166 | a = unoctchar(p[0]); 167 | if (a < 0) 168 | return -EINVAL; 169 | 170 | b = unoctchar(p[1]); 171 | if (b < 0) 172 | return -EINVAL; 173 | 174 | c = unoctchar(p[2]); 175 | if (c < 0) 176 | return -EINVAL; 177 | 178 | /* don't allow NUL bytes */ 179 | if (a == 0 && b == 0 && c == 0) 180 | return -EINVAL; 181 | 182 | /* Don't allow bytes above 255 */ 183 | m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; 184 | if (m > 255) 185 | return -EINVAL; 186 | 187 | *ret = m; 188 | *eight_bit = true; 189 | r = 3; 190 | break; 191 | } 192 | 193 | default: 194 | return -EINVAL; 195 | } 196 | 197 | return r; 198 | } 199 | -------------------------------------------------------------------------------- /src/share/escape.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "string-util.h" 12 | #include "missing.h" 13 | 14 | /* What characters are special in the shell? */ 15 | /* must be escaped outside and inside double-quotes */ 16 | #define SHELL_NEED_ESCAPE "\"\\`$" 17 | /* can be escaped or double-quoted */ 18 | #define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" 19 | 20 | typedef enum UnescapeFlags { 21 | UNESCAPE_RELAX = 1, 22 | } UnescapeFlags; 23 | 24 | int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); 25 | -------------------------------------------------------------------------------- /src/share/extract-word.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include "macro.h" 5 | 6 | typedef enum ExtractFlags { 7 | EXTRACT_RELAX = 1, 8 | EXTRACT_CUNESCAPE = 2, 9 | EXTRACT_CUNESCAPE_RELAX = 4, 10 | EXTRACT_QUOTES = 8, 11 | EXTRACT_DONT_COALESCE_SEPARATORS = 16, 12 | EXTRACT_RETAIN_ESCAPE = 32, 13 | } ExtractFlags; 14 | 15 | int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); 16 | -------------------------------------------------------------------------------- /src/share/fd-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "fd-util.h" 11 | #include "fs-util.h" 12 | #include "macro.h" 13 | #include "missing.h" 14 | #include "parse-util.h" 15 | #include "path-util.h" 16 | #include "socket-util.h" 17 | #include "stdio-util.h" 18 | #include "util.h" 19 | 20 | int close_nointr(int fd) { 21 | assert(fd >= 0); 22 | 23 | if (close(fd) >= 0) 24 | return 0; 25 | 26 | /* 27 | * Just ignore EINTR; a retry loop is the wrong thing to do on 28 | * Linux. 29 | * 30 | * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html 31 | * https://bugzilla.gnome.org/show_bug.cgi?id=682819 32 | * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR 33 | * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain 34 | */ 35 | if (errno == EINTR) 36 | return 0; 37 | 38 | return -errno; 39 | } 40 | 41 | int safe_close(int fd) { 42 | 43 | /* 44 | * Like close_nointr() but cannot fail. Guarantees errno is 45 | * unchanged. Is a NOP with negative fds passed, and returns 46 | * -1, so that it can be used in this syntax: 47 | * 48 | * fd = safe_close(fd); 49 | */ 50 | 51 | if (fd >= 0) { 52 | PROTECT_ERRNO; 53 | 54 | /* The kernel might return pretty much any error code 55 | * via close(), but the fd will be closed anyway. The 56 | * only condition we want to check for here is whether 57 | * the fd was invalid at all... */ 58 | 59 | assert_se(close_nointr(fd) != -EBADF); 60 | } 61 | 62 | return -1; 63 | } 64 | 65 | void close_many(const int fds[], unsigned n_fd) { 66 | unsigned i; 67 | 68 | assert(fds || n_fd <= 0); 69 | 70 | for (i = 0; i < n_fd; i++) 71 | safe_close(fds[i]); 72 | } 73 | 74 | int fclose_nointr(FILE *f) { 75 | assert(f); 76 | 77 | /* Same as close_nointr(), but for fclose() */ 78 | 79 | if (fclose(f) == 0) 80 | return 0; 81 | 82 | if (errno == EINTR) 83 | return 0; 84 | 85 | return -errno; 86 | } 87 | 88 | FILE* safe_fclose(FILE *f) { 89 | 90 | /* Same as safe_close(), but for fclose() */ 91 | 92 | if (f) { 93 | PROTECT_ERRNO; 94 | 95 | assert_se(fclose_nointr(f) != EBADF); 96 | } 97 | 98 | return NULL; 99 | } 100 | 101 | int fd_cloexec(int fd, bool cloexec) { 102 | int flags, nflags; 103 | 104 | assert(fd >= 0); 105 | 106 | flags = fcntl(fd, F_GETFD, 0); 107 | if (flags < 0) 108 | return -errno; 109 | 110 | if (cloexec) 111 | nflags = flags | FD_CLOEXEC; 112 | else 113 | nflags = flags & ~FD_CLOEXEC; 114 | 115 | if (nflags == flags) 116 | return 0; 117 | 118 | if (fcntl(fd, F_SETFD, nflags) < 0) 119 | return -errno; 120 | 121 | return 0; 122 | } 123 | 124 | int fd_nonblock(int fd, bool nonblock) { 125 | int flags, nflags; 126 | 127 | assert(fd >= 0); 128 | 129 | flags = fcntl(fd, F_GETFL, 0); 130 | if (flags < 0) 131 | return -errno; 132 | 133 | nflags = UPDATE_FLAG(flags, O_NONBLOCK, nonblock); 134 | if (nflags == flags) 135 | return 0; 136 | 137 | return RET_NERRNO(fcntl(fd, F_SETFL, nflags)); 138 | } 139 | 140 | void stdio_unset_cloexec(void) { 141 | fd_cloexec(STDIN_FILENO, false); 142 | fd_cloexec(STDOUT_FILENO, false); 143 | fd_cloexec(STDERR_FILENO, false); 144 | } 145 | 146 | void cmsg_close_all(struct msghdr *mh) { 147 | struct cmsghdr *cmsg; 148 | 149 | assert(mh); 150 | 151 | CMSG_FOREACH(cmsg, mh) 152 | if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) 153 | close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); 154 | } 155 | 156 | int fd_move_above_stdio(int fd) { 157 | int flags, copy; 158 | PROTECT_ERRNO; 159 | 160 | /* Moves the specified file descriptor if possible out of the range [0…2], i.e. the range of 161 | * stdin/stdout/stderr. If it can't be moved outside of this range the original file descriptor is 162 | * returned. This call is supposed to be used for long-lasting file descriptors we allocate in our code that 163 | * might get loaded into foreign code, and where we want ensure our fds are unlikely used accidentally as 164 | * stdin/stdout/stderr of unrelated code. 165 | * 166 | * Note that this doesn't fix any real bugs, it just makes it less likely that our code will be affected by 167 | * buggy code from others that mindlessly invokes 'fprintf(stderr, …' or similar in places where stderr has 168 | * been closed before. 169 | * 170 | * This function is written in a "best-effort" and "least-impact" style. This means whenever we encounter an 171 | * error we simply return the original file descriptor, and we do not touch errno. */ 172 | 173 | if (fd < 0 || fd > 2) 174 | return fd; 175 | 176 | flags = fcntl(fd, F_GETFD, 0); 177 | if (flags < 0) 178 | return fd; 179 | 180 | if (flags & FD_CLOEXEC) 181 | copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); 182 | else 183 | copy = fcntl(fd, F_DUPFD, 3); 184 | if (copy < 0) 185 | return fd; 186 | 187 | assert(copy > 2); 188 | 189 | (void) close(fd); 190 | return copy; 191 | } 192 | -------------------------------------------------------------------------------- /src/share/fd-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "macro.h" 10 | 11 | /* Make sure we can distinguish fd 0 and NULL */ 12 | #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) 13 | #define PTR_TO_FD(p) (PTR_TO_INT(p)-1) 14 | 15 | int close_nointr(int fd); 16 | int safe_close(int fd); 17 | 18 | void close_many(const int fds[], unsigned n_fd); 19 | 20 | int fclose_nointr(FILE *f); 21 | FILE* safe_fclose(FILE *f); 22 | 23 | static inline void closep(int *fd) { 24 | safe_close(*fd); 25 | } 26 | 27 | static inline void fclosep(FILE **f) { 28 | safe_fclose(*f); 29 | } 30 | 31 | DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); 32 | DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); 33 | 34 | #define _cleanup_close_ _cleanup_(closep) 35 | #define _cleanup_fclose_ _cleanup_(fclosep) 36 | #define _cleanup_pclose_ _cleanup_(pclosep) 37 | #define _cleanup_closedir_ _cleanup_(closedirp) 38 | #define _cleanup_close_pair_ _cleanup_(close_pairp) 39 | 40 | int fd_cloexec(int fd, bool cloexec); 41 | int fd_nonblock(int fd, bool nonblock); 42 | void stdio_unset_cloexec(void); 43 | 44 | int fd_move_above_stdio(int fd); 45 | 46 | void cmsg_close_all(struct msghdr *mh); 47 | 48 | 49 | /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ 50 | #define ERRNO_IS_DISCONNECT(r) \ 51 | IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) 52 | 53 | /* Like TAKE_PTR() but for file descriptors, resetting them to -1 */ 54 | #define TAKE_FD(fd) \ 55 | ({ \ 56 | int *_fd_ = &(fd); \ 57 | int _ret_ = *_fd_; \ 58 | *_fd_ = -1; \ 59 | _ret_; \ 60 | }) 61 | -------------------------------------------------------------------------------- /src/share/fileio.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | #include "time-util.h" 12 | 13 | typedef enum { 14 | WRITE_STRING_FILE_CREATE = 1, 15 | WRITE_STRING_FILE_ATOMIC = 2, 16 | WRITE_STRING_FILE_AVOID_NEWLINE = 4, 17 | WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8, 18 | } WriteStringFileFlags; 19 | 20 | int write_string_stream(FILE *f, const char *line, bool enforce_newline); 21 | 22 | int read_one_line_file(const char *fn, char **line); 23 | int read_full_file(const char *fn, char **contents, size_t *size); 24 | int read_full_stream(FILE *f, char **contents, size_t *size); 25 | 26 | int verify_file(const char *fn, const char *blob, bool accept_extra_nl); 27 | 28 | int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; 29 | 30 | #define FOREACH_LINE(line, f, on_error) \ 31 | for (;;) \ 32 | if (!fgets(line, sizeof(line), f)) { \ 33 | if (ferror(f)) { \ 34 | on_error; \ 35 | } \ 36 | break; \ 37 | } else 38 | 39 | int fflush_and_check(FILE *f); 40 | 41 | int fopen_temporary(const char *path, FILE **_f, char **_temp_path); 42 | int mkostemp_safe(char *pattern, int flags); 43 | 44 | int tempfn_xxxxxx(const char *p, const char *extra, char **ret); 45 | -------------------------------------------------------------------------------- /src/share/formats-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #if SIZEOF_PID_T == 4 7 | # define PID_PRI PRIi32 8 | #elif SIZEOF_PID_T == 2 9 | # define PID_PRI PRIi16 10 | #else 11 | # error Unknown pid_t size 12 | #endif 13 | #define PID_FMT "%" PID_PRI 14 | 15 | #if SIZEOF_UID_T == 4 16 | # define UID_FMT "%" PRIu32 17 | #elif SIZEOF_UID_T == 2 18 | # define UID_FMT "%" PRIu16 19 | #else 20 | # error Unknown uid_t size 21 | #endif 22 | 23 | #if SIZEOF_GID_T == 4 24 | # define GID_FMT "%" PRIu32 25 | #elif SIZEOF_GID_T == 2 26 | # define GID_FMT "%" PRIu16 27 | #else 28 | # error Unknown gid_t size 29 | #endif 30 | 31 | #if SIZEOF_TIME_T == 8 32 | # define PRI_TIME PRIi64 33 | #elif SIZEOF_TIME_T == 4 34 | # define PRI_TIME "li" 35 | #else 36 | # error Unknown time_t size 37 | #endif 38 | 39 | #if SIZEOF_RLIM_T == 8 40 | # define RLIM_FMT "%" PRIu64 41 | #elif SIZEOF_RLIM_T == 4 42 | # define RLIM_FMT "%" PRIu32 43 | #else 44 | # error Unknown rlim_t size 45 | #endif 46 | 47 | #if SIZEOF_DEV_T == 8 48 | # define DEV_FMT "%" PRIu64 49 | #elif SIZEOF_DEV_T == 4 50 | # define DEV_FMT "%" PRIu32 51 | #else 52 | # error Unknown dev_t size 53 | #endif 54 | 55 | #if SIZEOF_INO_T == 8 56 | # define INO_FMT "%" PRIu64 57 | #elif SIZEOF_INO_T == 4 58 | # define INO_FMT "%" PRIu32 59 | #else 60 | # error Unknown ino_t size 61 | #endif 62 | -------------------------------------------------------------------------------- /src/share/fs-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "alloc-util.h" 14 | #include "dirent-util.h" 15 | #include "fd-util.h" 16 | #include "fileio.h" 17 | #include "fs-util.h" 18 | #include "log.h" 19 | #include "macro.h" 20 | #include "missing.h" 21 | #include "mkdir.h" 22 | #include "parse-util.h" 23 | #include "path-util.h" 24 | #include "stat-util.h" 25 | #include "stdio-util.h" 26 | #include "string-util.h" 27 | #include "strv.h" 28 | #include "time-util.h" 29 | #include "user-util.h" 30 | #include "util.h" 31 | 32 | int unlink_noerrno(const char *path) { 33 | PROTECT_ERRNO; 34 | int r; 35 | 36 | r = unlink(path); 37 | if (r < 0) 38 | return -errno; 39 | 40 | return 0; 41 | } 42 | 43 | int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { 44 | assert(path); 45 | 46 | /* Under the assumption that we are running privileged we 47 | * first change the access mode and only then hand out 48 | * ownership to avoid a window where access is too open. */ 49 | 50 | if (mode != MODE_INVALID) 51 | if (chmod(path, mode) < 0) 52 | return -errno; 53 | 54 | if (uid != UID_INVALID || gid != GID_INVALID) 55 | if (chown(path, uid, gid) < 0) 56 | return -errno; 57 | 58 | return 0; 59 | } 60 | 61 | int fchmod_umask(int fd, mode_t m) { 62 | mode_t u; 63 | int r; 64 | 65 | u = umask(0777); 66 | r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; 67 | umask(u); 68 | 69 | return r; 70 | } 71 | 72 | int fd_warn_permissions(const char *path, int fd) { 73 | struct stat st; 74 | 75 | if (fstat(fd, &st) < 0) 76 | return -errno; 77 | 78 | if (st.st_mode & 0111) 79 | log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); 80 | 81 | if (st.st_mode & 0002) 82 | log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); 83 | 84 | if (getpid() == 1 && (st.st_mode & 0044) != 0044) 85 | log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); 86 | 87 | return 0; 88 | } 89 | 90 | int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { 91 | _cleanup_close_ int fd; 92 | int r; 93 | 94 | assert(path); 95 | 96 | if (parents) 97 | mkdir_parents(path, 0755); 98 | 99 | fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 100 | (mode == 0 || mode == MODE_INVALID) ? 0644 : mode); 101 | if (fd < 0) 102 | return -errno; 103 | 104 | if (mode != MODE_INVALID) { 105 | r = fchmod(fd, mode); 106 | if (r < 0) 107 | return -errno; 108 | } 109 | 110 | if (uid != UID_INVALID || gid != GID_INVALID) { 111 | r = fchown(fd, uid, gid); 112 | if (r < 0) 113 | return -errno; 114 | } 115 | 116 | if (stamp != USEC_INFINITY) { 117 | struct timespec ts[2]; 118 | 119 | timespec_store(&ts[0], stamp); 120 | ts[1] = ts[0]; 121 | r = futimens(fd, ts); 122 | } else 123 | r = futimens(fd, NULL); 124 | if (r < 0) 125 | return -errno; 126 | 127 | return 0; 128 | } 129 | 130 | int touch(const char *path) { 131 | return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); 132 | } 133 | 134 | int inotify_add_watch_fd(int fd, int what, uint32_t mask) { 135 | char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; 136 | int r; 137 | 138 | /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ 139 | xsprintf(path, "/proc/self/fd/%i", what); 140 | 141 | r = inotify_add_watch(fd, path, mask); 142 | if (r < 0) 143 | return -errno; 144 | 145 | return r; 146 | } 147 | -------------------------------------------------------------------------------- /src/share/fs-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "time-util.h" 13 | 14 | int unlink_noerrno(const char *path); 15 | 16 | int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); 17 | 18 | int fchmod_umask(int fd, mode_t mode); 19 | 20 | int fd_warn_permissions(const char *path, int fd); 21 | 22 | #define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) 23 | 24 | int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); 25 | int touch(const char *path); 26 | 27 | #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) 28 | 29 | #define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ 30 | for ((e) = &buffer.ev; \ 31 | (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ 32 | (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) 33 | 34 | union inotify_event_buffer { 35 | struct inotify_event ev; 36 | uint8_t raw[INOTIFY_EVENT_MAX]; 37 | }; 38 | 39 | int inotify_add_watch_fd(int fd, int what, uint32_t mask); 40 | -------------------------------------------------------------------------------- /src/share/hash-funcs.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include "hash-funcs.h" 4 | 5 | void string_hash_func(const void *p, struct siphash *state) { 6 | siphash24_compress(p, strlen(p) + 1, state); 7 | } 8 | 9 | int string_compare_func(const void *a, const void *b) { 10 | return strcmp(a, b); 11 | } 12 | 13 | const struct hash_ops string_hash_ops = { 14 | .hash = string_hash_func, 15 | .compare = string_compare_func 16 | }; 17 | 18 | void trivial_hash_func(const void *p, struct siphash *state) { 19 | siphash24_compress(&p, sizeof(p), state); 20 | } 21 | 22 | int trivial_compare_func(const void *a, const void *b) { 23 | return a < b ? -1 : (a > b ? 1 : 0); 24 | } 25 | 26 | const struct hash_ops trivial_hash_ops = { 27 | .hash = trivial_hash_func, 28 | .compare = trivial_compare_func 29 | }; 30 | 31 | void uint64_hash_func(const void *p, struct siphash *state) { 32 | siphash24_compress(p, sizeof(uint64_t), state); 33 | } 34 | 35 | int uint64_compare_func(const void *_a, const void *_b) { 36 | uint64_t a, b; 37 | a = *(const uint64_t*) _a; 38 | b = *(const uint64_t*) _b; 39 | return a < b ? -1 : (a > b ? 1 : 0); 40 | } 41 | 42 | const struct hash_ops uint64_hash_ops = { 43 | .hash = uint64_hash_func, 44 | .compare = uint64_compare_func 45 | }; 46 | 47 | #if SIZEOF_DEV_T != 8 48 | void devt_hash_func(const void *p, struct siphash *state) { 49 | siphash24_compress(p, sizeof(dev_t), state); 50 | } 51 | 52 | int devt_compare_func(const void *_a, const void *_b) { 53 | dev_t a, b; 54 | a = *(const dev_t*) _a; 55 | b = *(const dev_t*) _b; 56 | return a < b ? -1 : (a > b ? 1 : 0); 57 | } 58 | 59 | const struct hash_ops devt_hash_ops = { 60 | .hash = devt_hash_func, 61 | .compare = devt_compare_func 62 | }; 63 | #endif 64 | -------------------------------------------------------------------------------- /src/share/hash-funcs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "macro.h" 6 | #include "siphash24.h" 7 | 8 | typedef void (*hash_func_t)(const void *p, struct siphash *state); 9 | typedef int (*compare_func_t)(const void *a, const void *b); 10 | 11 | struct hash_ops { 12 | hash_func_t hash; 13 | compare_func_t compare; 14 | }; 15 | 16 | void string_hash_func(const void *p, struct siphash *state); 17 | int string_compare_func(const void *a, const void *b) _pure_; 18 | extern const struct hash_ops string_hash_ops; 19 | 20 | /* This will compare the passed pointers directly, and will not 21 | * dereference them. This is hence not useful for strings or 22 | * suchlike. */ 23 | void trivial_hash_func(const void *p, struct siphash *state); 24 | int trivial_compare_func(const void *a, const void *b) _const_; 25 | extern const struct hash_ops trivial_hash_ops; 26 | 27 | /* 32bit values we can always just embed in the pointer itself, but 28 | * in order to support 32bit archs we need store 64bit values 29 | * indirectly, since they don't fit in a pointer. */ 30 | void uint64_hash_func(const void *p, struct siphash *state); 31 | int uint64_compare_func(const void *a, const void *b) _pure_; 32 | extern const struct hash_ops uint64_hash_ops; 33 | 34 | /* On some archs dev_t is 32bit, and on others 64bit. And sometimes 35 | * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ 36 | #if SIZEOF_DEV_T != 8 37 | void devt_hash_func(const void *p, struct siphash *state) _pure_; 38 | int devt_compare_func(const void *a, const void *b) _pure_; 39 | extern const struct hash_ops devt_hash_ops = { 40 | .hash = devt_hash_func, 41 | .compare = devt_compare_func 42 | }; 43 | #else 44 | #define devt_hash_func uint64_hash_func 45 | #define devt_compare_func uint64_compare_func 46 | #define devt_hash_ops uint64_hash_ops 47 | #endif 48 | -------------------------------------------------------------------------------- /src/share/hexdecoct.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "alloc-util.h" 9 | #include "hexdecoct.h" 10 | #include "macro.h" 11 | #include "util.h" 12 | 13 | char octchar(int x) { 14 | return '0' + (x & 7); 15 | } 16 | 17 | int unoctchar(char c) { 18 | 19 | if (c >= '0' && c <= '7') 20 | return c - '0'; 21 | 22 | return -EINVAL; 23 | } 24 | 25 | char decchar(int x) { 26 | return '0' + (x % 10); 27 | } 28 | 29 | int undecchar(char c) { 30 | 31 | if (c >= '0' && c <= '9') 32 | return c - '0'; 33 | 34 | return -EINVAL; 35 | } 36 | 37 | char hexchar(int x) { 38 | __attribute__ ((nonstring)) 39 | static const char table[16] = "0123456789abcdef"; 40 | 41 | return table[x & 15]; 42 | } 43 | 44 | int unhexchar(char c) { 45 | 46 | if (c >= '0' && c <= '9') 47 | return c - '0'; 48 | 49 | if (c >= 'a' && c <= 'f') 50 | return c - 'a' + 10; 51 | 52 | if (c >= 'A' && c <= 'F') 53 | return c - 'A' + 10; 54 | 55 | return -EINVAL; 56 | } 57 | -------------------------------------------------------------------------------- /src/share/hexdecoct.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "macro.h" 10 | 11 | char octchar(int x) _const_; 12 | int unoctchar(char c) _const_; 13 | 14 | char decchar(int x) _const_; 15 | int undecchar(char c) _const_; 16 | 17 | char hexchar(int x) _const_; 18 | int unhexchar(char c) _const_; 19 | -------------------------------------------------------------------------------- /src/share/hostname-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "alloc-util.h" 11 | #include "hostname-util.h" 12 | #include "string-util.h" 13 | #include "strv.h" 14 | 15 | bool valid_ldh_char(char c) { 16 | /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ 17 | 18 | return ascii_isalpha(c) || 19 | ascii_isdigit(c) || 20 | c == '-'; 21 | } 22 | 23 | bool hostname_is_valid(const char *s, ValidHostnameFlags flags) { 24 | unsigned n_dots = 0; 25 | const char *p; 26 | bool dot, hyphen; 27 | 28 | /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only 29 | * checks if the name is composed of allowed characters and the length is not above the maximum 30 | * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if 31 | * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note 32 | * that due to the restricted charset and length this call is substantially more conservative than 33 | * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames 34 | * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */ 35 | 36 | if (isempty(s)) 37 | return false; 38 | 39 | if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */ 40 | return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST); 41 | 42 | for (p = s, dot = hyphen = true; *p; p++) 43 | if (*p == '.') { 44 | if (dot || hyphen) 45 | return false; 46 | 47 | dot = true; 48 | hyphen = false; 49 | n_dots++; 50 | 51 | } else if (*p == '-') { 52 | if (dot) 53 | return false; 54 | 55 | dot = false; 56 | hyphen = true; 57 | 58 | } else { 59 | if (!valid_ldh_char(*p)) 60 | return false; 61 | 62 | dot = false; 63 | hyphen = false; 64 | } 65 | 66 | if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT))) 67 | return false; 68 | if (hyphen) 69 | return false; 70 | 71 | if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to 72 | * 255 characters */ 73 | return false; 74 | 75 | return true; 76 | } 77 | 78 | char* hostname_cleanup(char *s) { 79 | char *p, *d; 80 | bool dot, hyphen; 81 | 82 | assert(s); 83 | 84 | for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++) 85 | if (*p == '.') { 86 | if (dot || hyphen) 87 | continue; 88 | 89 | *(d++) = '.'; 90 | dot = true; 91 | hyphen = false; 92 | 93 | } else if (*p == '-') { 94 | if (dot) 95 | continue; 96 | 97 | *(d++) = '-'; 98 | dot = false; 99 | hyphen = true; 100 | 101 | } else if (valid_ldh_char(*p)) { 102 | *(d++) = *p; 103 | dot = false; 104 | hyphen = false; 105 | } 106 | 107 | if (d > s && IN_SET(d[-1], '-', '.')) 108 | /* The dot can occur at most once, but we might have multiple 109 | * hyphens, hence the loop */ 110 | d--; 111 | *d = 0; 112 | 113 | return s; 114 | } 115 | -------------------------------------------------------------------------------- /src/share/hostname-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "macro.h" 8 | #include "strv.h" 9 | 10 | typedef enum GetHostnameFlags { 11 | GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 0, /* accepts "localhost" or friends. */ 12 | GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 1, /* use default hostname if no hostname is set. */ 13 | GET_HOSTNAME_SHORT = 1 << 2, /* kills the FQDN part if present. */ 14 | } GetHostnameFlags; 15 | 16 | int gethostname_full(GetHostnameFlags flags, char **ret); 17 | static inline int gethostname_strict(char **ret) { 18 | return gethostname_full(0, ret); 19 | } 20 | 21 | static inline char* gethostname_malloc(void) { 22 | char *s; 23 | 24 | if (gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT, &s) < 0) 25 | return NULL; 26 | 27 | return s; 28 | } 29 | 30 | static inline char* gethostname_short_malloc(void) { 31 | char *s; 32 | 33 | if (gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT | GET_HOSTNAME_SHORT, &s) < 0) 34 | return NULL; 35 | 36 | return s; 37 | } 38 | 39 | char* get_default_hostname(void); 40 | 41 | bool valid_ldh_char(char c) _const_; 42 | 43 | typedef enum ValidHostnameFlags { 44 | VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */ 45 | VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */ 46 | } ValidHostnameFlags; 47 | 48 | bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_; 49 | char* hostname_cleanup(char *s); 50 | 51 | bool is_localhost(const char *hostname); 52 | 53 | int get_pretty_hostname(char **ret); 54 | -------------------------------------------------------------------------------- /src/share/in-addr-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "macro.h" 9 | #include "util.h" 10 | 11 | union in_addr_union { 12 | struct in_addr in; 13 | struct in6_addr in6; 14 | }; 15 | 16 | struct in_addr_data { 17 | int family; 18 | union in_addr_union address; 19 | }; 20 | 21 | bool in4_addr_is_null(const struct in_addr *a); 22 | bool in6_addr_is_null(const struct in6_addr *a); 23 | 24 | int in_addr_is_null(int family, const union in_addr_union *u); 25 | int in_addr_is_link_local(int family, const union in_addr_union *u); 26 | int in_addr_is_localhost(int family, const union in_addr_union *u); 27 | int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); 28 | int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); 29 | int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); 30 | int in_addr_to_string(int family, const union in_addr_union *u, char **ret); 31 | int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); 32 | int in_addr_from_string(int family, const char *s, union in_addr_union *ret); 33 | int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret); 34 | int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex); 35 | unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr); 36 | struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen); 37 | int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); 38 | int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); 39 | int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen); 40 | 41 | static inline size_t FAMILY_ADDRESS_SIZE(int family) { 42 | assert(family == AF_INET || family == AF_INET6); 43 | return family == AF_INET6 ? 16 : 4; 44 | } 45 | 46 | #define IN_ADDR_NULL ((union in_addr_union) {}) 47 | 48 | /* Note: the lifetime of the compound literal is the immediately surrounding block, 49 | * see C11 §6.5.2.5, and 50 | * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */ 51 | #define IN_ADDR_MAX CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) 52 | #define IN_ADDR_TO_STRING(family, addr) typesafe_inet_ntop(family, addr, (char[IN_ADDR_MAX]){}, IN_ADDR_MAX) 53 | #define IN4_ADDR_TO_STRING(addr) typesafe_inet_ntop4(addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN) 54 | #define IN6_ADDR_TO_STRING(addr) typesafe_inet_ntop6(addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN) 55 | -------------------------------------------------------------------------------- /src/share/io-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "io-util.h" 11 | #include "time-util.h" 12 | 13 | ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { 14 | uint8_t *p = buf; 15 | ssize_t n = 0; 16 | 17 | assert(fd >= 0); 18 | assert(buf); 19 | 20 | /* If called with nbytes == 0, let's call read() at least 21 | * once, to validate the operation */ 22 | 23 | if (nbytes > (size_t) SSIZE_MAX) 24 | return -EINVAL; 25 | 26 | do { 27 | ssize_t k; 28 | 29 | k = read(fd, p, nbytes); 30 | if (k < 0) { 31 | if (errno == EINTR) 32 | continue; 33 | 34 | if (errno == EAGAIN && do_poll) { 35 | 36 | /* We knowingly ignore any return value here, 37 | * and expect that any error/EOF is reported 38 | * via read() */ 39 | 40 | (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); 41 | continue; 42 | } 43 | 44 | return n > 0 ? n : -errno; 45 | } 46 | 47 | if (k == 0) 48 | return n; 49 | 50 | assert((size_t) k <= nbytes); 51 | 52 | p += k; 53 | nbytes -= k; 54 | n += k; 55 | } while (nbytes > 0); 56 | 57 | return n; 58 | } 59 | 60 | int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { 61 | ssize_t n; 62 | 63 | n = loop_read(fd, buf, nbytes, do_poll); 64 | if (n < 0) 65 | return (int) n; 66 | if ((size_t) n != nbytes) 67 | return -EIO; 68 | 69 | return 0; 70 | } 71 | 72 | int fd_wait_for_event(int fd, int event, usec_t t) { 73 | 74 | struct pollfd pollfd = { 75 | .fd = fd, 76 | .events = event, 77 | }; 78 | 79 | struct timespec ts; 80 | int r; 81 | 82 | r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); 83 | if (r < 0) 84 | return -errno; 85 | 86 | if (r == 0) 87 | return 0; 88 | 89 | return pollfd.revents; 90 | } 91 | -------------------------------------------------------------------------------- /src/share/io-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "macro.h" 12 | #include "time-util.h" 13 | 14 | ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); 15 | int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); 16 | 17 | int fd_wait_for_event(int fd, int event, usec_t timeout); 18 | 19 | #define IOVEC_SET_STRING(i, s) \ 20 | do { \ 21 | struct iovec *_i = &(i); \ 22 | char *_s = (char *)(s); \ 23 | _i->iov_base = _s; \ 24 | _i->iov_len = strlen(_s); \ 25 | } while (false) 26 | 27 | static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { 28 | unsigned j; 29 | size_t r = 0; 30 | 31 | for (j = 0; j < n; j++) 32 | r += i[j].iov_len; 33 | 34 | return r; 35 | } 36 | 37 | static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { 38 | unsigned j; 39 | 40 | for (j = 0; j < n; j++) { 41 | size_t sub; 42 | 43 | if (_unlikely_(k <= 0)) 44 | break; 45 | 46 | sub = MIN(i[j].iov_len, k); 47 | i[j].iov_len -= sub; 48 | i[j].iov_base = (uint8_t*) i[j].iov_base + sub; 49 | k -= sub; 50 | } 51 | 52 | return k; 53 | } 54 | 55 | static inline bool FILE_SIZE_VALID(uint64_t l) { 56 | /* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than 57 | * 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */ 58 | 59 | return (l >> 63) == 0; 60 | } 61 | 62 | static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { 63 | 64 | /* Same as above, but allows one extra value: -1 as indication for infinity. */ 65 | 66 | if (l == (uint64_t) -1) 67 | return true; 68 | 69 | return FILE_SIZE_VALID(l); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/share/ioprio.h: -------------------------------------------------------------------------------- 1 | #ifndef IOPRIO_H 2 | #define IOPRIO_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * Gives us 8 prio classes with 13-bits of data for each class 9 | */ 10 | #define IOPRIO_BITS (16) 11 | #define IOPRIO_CLASS_SHIFT (13) 12 | #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) 13 | 14 | #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) 15 | #define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) 16 | #define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) 17 | 18 | #define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) 19 | 20 | /* 21 | * These are the io priority groups as implemented by CFQ. RT is the realtime 22 | * class, it always gets premium service. BE is the best-effort scheduling 23 | * class, the default for any process. IDLE is the idle scheduling class, it 24 | * is only served when no one else is using the disk. 25 | */ 26 | enum { 27 | IOPRIO_CLASS_NONE, 28 | IOPRIO_CLASS_RT, 29 | IOPRIO_CLASS_BE, 30 | IOPRIO_CLASS_IDLE, 31 | }; 32 | 33 | /* 34 | * 8 best effort priority levels are supported 35 | */ 36 | #define IOPRIO_BE_NR (8) 37 | 38 | enum { 39 | IOPRIO_WHO_PROCESS = 1, 40 | IOPRIO_WHO_PGRP, 41 | IOPRIO_WHO_USER, 42 | }; 43 | 44 | static inline int ioprio_set(int which, int who, int ioprio) { 45 | return syscall(__NR_ioprio_set, which, who, ioprio); 46 | } 47 | 48 | static inline int ioprio_get(int which, int who) { 49 | return syscall(__NR_ioprio_get, which, who); 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/share/iovec-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include "iovec-util.h" 4 | #include "string-util.h" 5 | 6 | size_t iovec_total_size(const struct iovec *iovec, size_t n) { 7 | size_t sum = 0; 8 | 9 | assert(iovec || n == 0); 10 | 11 | FOREACH_ARRAY(j, iovec, n) 12 | sum += j->iov_len; 13 | 14 | return sum; 15 | } 16 | 17 | bool iovec_increment(struct iovec *iovec, size_t n, size_t k) { 18 | assert(iovec || n == 0); 19 | 20 | /* Returns true if there is nothing else to send (bytes written cover all of the iovec), 21 | * false if there's still work to do. */ 22 | 23 | FOREACH_ARRAY(j, iovec, n) { 24 | size_t sub; 25 | 26 | if (j->iov_len == 0) 27 | continue; 28 | if (k == 0) 29 | return false; 30 | 31 | sub = MIN(j->iov_len, k); 32 | j->iov_len -= sub; 33 | j->iov_base = (uint8_t*) j->iov_base + sub; 34 | k -= sub; 35 | } 36 | 37 | assert(k == 0); /* Anything else would mean that we wrote more bytes than available, 38 | * or the kernel reported writing more bytes than sent. */ 39 | return true; 40 | } 41 | 42 | void iovec_array_free(struct iovec *iovec, size_t n_iovec) { 43 | assert(iovec || n_iovec == 0); 44 | 45 | FOREACH_ARRAY(i, iovec, n_iovec) 46 | free(i->iov_base); 47 | 48 | free(iovec); 49 | } 50 | -------------------------------------------------------------------------------- /src/share/iovec-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "alloc-util.h" 10 | #include "macro.h" 11 | 12 | /* An iovec pointing to a single NUL byte */ 13 | #define IOVEC_NUL_BYTE (const struct iovec) { \ 14 | .iov_base = (void*) (const uint8_t[1]) { 0 }, \ 15 | .iov_len = 1, \ 16 | } 17 | 18 | size_t iovec_total_size(const struct iovec *iovec, size_t n); 19 | 20 | bool iovec_increment(struct iovec *iovec, size_t n, size_t k); 21 | 22 | /* This accepts both const and non-const pointers */ 23 | #define IOVEC_MAKE(base, len) \ 24 | (struct iovec) { \ 25 | .iov_base = (void*) (base), \ 26 | .iov_len = (len), \ 27 | } 28 | 29 | static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s) { 30 | assert(iovec); 31 | /* We don't use strlen_ptr() here, because we don't want to include string-util.h for now */ 32 | *iovec = IOVEC_MAKE(s, s ? strlen(s) : 0); 33 | return iovec; 34 | } 35 | 36 | #define IOVEC_MAKE_STRING(s) \ 37 | *iovec_make_string(&(struct iovec) {}, s) 38 | 39 | #define CONST_IOVEC_MAKE_STRING(s) \ 40 | (const struct iovec) { \ 41 | .iov_base = (char*) s, \ 42 | .iov_len = STRLEN(s), \ 43 | } 44 | 45 | static inline void iovec_done(struct iovec *iovec) { 46 | /* A _cleanup_() helper that frees the iov_base in the iovec */ 47 | assert(iovec); 48 | 49 | iovec->iov_base = mfree(iovec->iov_base); 50 | iovec->iov_len = 0; 51 | } 52 | 53 | static inline bool iovec_is_set(const struct iovec *iovec) { 54 | /* Checks if the iovec points to a non-empty chunk of memory */ 55 | return iovec && iovec->iov_len > 0 && iovec->iov_base; 56 | } 57 | 58 | static inline bool iovec_is_valid(const struct iovec *iovec) { 59 | /* Checks if the iovec is either NULL, empty or points to a valid bit of memory */ 60 | return !iovec || (iovec->iov_base || iovec->iov_len == 0); 61 | } 62 | 63 | char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); 64 | char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value); 65 | 66 | void iovec_array_free(struct iovec *iovec, size_t n_iovec); 67 | -------------------------------------------------------------------------------- /src/share/mempool.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | 6 | #include "macro.h" 7 | #include "mempool.h" 8 | #include "util.h" 9 | 10 | struct pool { 11 | struct pool *next; 12 | unsigned n_tiles; 13 | unsigned n_used; 14 | }; 15 | 16 | void* mempool_alloc_tile(struct mempool *mp) { 17 | unsigned i; 18 | 19 | /* When a tile is released we add it to the list and simply 20 | * place the next pointer at its offset 0. */ 21 | 22 | assert(mp->tile_size >= sizeof(void*)); 23 | assert(mp->at_least > 0); 24 | 25 | if (mp->freelist) { 26 | void *r; 27 | 28 | r = mp->freelist; 29 | mp->freelist = * (void**) mp->freelist; 30 | return r; 31 | } 32 | 33 | if (_unlikely_(!mp->first_pool) || 34 | _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { 35 | unsigned n; 36 | size_t size; 37 | struct pool *p; 38 | 39 | n = mp->first_pool ? mp->first_pool->n_tiles : 0; 40 | n = MAX(mp->at_least, n * 2); 41 | size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size); 42 | n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; 43 | 44 | p = malloc(size); 45 | if (!p) 46 | return NULL; 47 | 48 | p->next = mp->first_pool; 49 | p->n_tiles = n; 50 | p->n_used = 0; 51 | 52 | mp->first_pool = p; 53 | } 54 | 55 | i = mp->first_pool->n_used++; 56 | 57 | return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size; 58 | } 59 | 60 | void* mempool_alloc0_tile(struct mempool *mp) { 61 | void *p; 62 | 63 | p = mempool_alloc_tile(mp); 64 | if (p) 65 | memzero(p, mp->tile_size); 66 | return p; 67 | } 68 | 69 | void mempool_free_tile(struct mempool *mp, void *p) { 70 | * (void**) p = mp->freelist; 71 | mp->freelist = p; 72 | } 73 | -------------------------------------------------------------------------------- /src/share/mempool.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | struct pool; 8 | 9 | struct mempool { 10 | struct pool *first_pool; 11 | void *freelist; 12 | size_t tile_size; 13 | unsigned at_least; 14 | }; 15 | 16 | void* mempool_alloc_tile(struct mempool *mp); 17 | void* mempool_alloc0_tile(struct mempool *mp); 18 | void mempool_free_tile(struct mempool *mp, void *p); 19 | 20 | #define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ 21 | static struct mempool pool_name = { \ 22 | .tile_size = sizeof(tile_type), \ 23 | .at_least = alloc_at_least, \ 24 | } 25 | 26 | 27 | #ifdef VALGRIND 28 | void mempool_drop(struct mempool *mp); 29 | #endif 30 | -------------------------------------------------------------------------------- /src/share/missing.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | /* Missing glibc definitions to access certain kernel APIs */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef ARCH_MIPS 25 | #include 26 | #endif 27 | 28 | #ifdef HAVE_LINUX_BTRFS_H 29 | #include 30 | #endif 31 | 32 | #include "macro.h" 33 | 34 | #if defined(__i386__) || defined(__x86_64__) 35 | 36 | /* The precise definition of __O_TMPFILE is arch specific, so let's 37 | * just define this on x86 where we know the value. */ 38 | 39 | #ifndef __O_TMPFILE 40 | #define __O_TMPFILE 020000000 41 | #endif 42 | 43 | /* a horrid kludge trying to make sure that this will fail on old kernels */ 44 | #ifndef O_TMPFILE 45 | #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) 46 | #endif 47 | 48 | #endif 49 | 50 | #ifndef HAVE_KEY_SERIAL_T 51 | typedef int32_t key_serial_t; 52 | #endif 53 | 54 | #include "missing_syscall.h" 55 | -------------------------------------------------------------------------------- /src/share/missing_syscall.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | /* Missing glibc definitions to access certain kernel APIs */ 6 | 7 | /* ======================================================================= */ 8 | 9 | #if !HAVE_GETRANDOM 10 | # ifndef __NR_getrandom 11 | # if defined __x86_64__ 12 | # define __NR_getrandom 318 13 | # elif defined(__i386__) 14 | # define __NR_getrandom 355 15 | # elif defined(__arm__) 16 | # define __NR_getrandom 384 17 | # elif defined(__aarch64__) 18 | # define __NR_getrandom 278 19 | # elif defined(__ia64__) 20 | # define __NR_getrandom 1339 21 | # elif defined(__m68k__) 22 | # define __NR_getrandom 352 23 | # elif defined(__s390x__) 24 | # define __NR_getrandom 349 25 | # elif defined(__powerpc__) 26 | # define __NR_getrandom 359 27 | # elif defined _MIPS_SIM 28 | # if _MIPS_SIM == _MIPS_SIM_ABI32 29 | # define __NR_getrandom 4353 30 | # endif 31 | # if _MIPS_SIM == _MIPS_SIM_NABI32 32 | # define __NR_getrandom 6317 33 | # endif 34 | # if _MIPS_SIM == _MIPS_SIM_ABI64 35 | # define __NR_getrandom 5313 36 | # endif 37 | # else 38 | # warning "__NR_getrandom unknown for your architecture" 39 | # endif 40 | # endif 41 | 42 | static inline int getrandom(void *buffer, size_t count, unsigned flags) { 43 | # ifdef __NR_getrandom 44 | return syscall(__NR_getrandom, buffer, count, flags); 45 | # else 46 | errno = ENOSYS; 47 | return -1; 48 | # endif 49 | } 50 | #endif 51 | 52 | /* ======================================================================= */ 53 | 54 | static inline pid_t raw_getpid(void) { 55 | #if defined(__alpha__) 56 | return (pid_t) syscall(__NR_getxpid); 57 | #else 58 | return (pid_t) syscall(__NR_getpid); 59 | #endif 60 | } 61 | -------------------------------------------------------------------------------- /src/share/mkdir.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "fs-util.h" 9 | #include "macro.h" 10 | #include "mkdir.h" 11 | #include "path-util.h" 12 | #include "stat-util.h" 13 | #include "user-util.h" 14 | 15 | int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { 16 | struct stat st; 17 | 18 | if (_mkdir(path, mode) >= 0) 19 | if (chmod_and_chown(path, mode, uid, gid) < 0) 20 | return -errno; 21 | 22 | if (lstat(path, &st) < 0) 23 | return -errno; 24 | 25 | if ((st.st_mode & 0007) > (mode & 0007) || 26 | (st.st_mode & 0070) > (mode & 0070) || 27 | (st.st_mode & 0700) > (mode & 0700) || 28 | (uid != UID_INVALID && st.st_uid != uid) || 29 | (gid != GID_INVALID && st.st_gid != gid) || 30 | !S_ISDIR(st.st_mode)) 31 | return -EEXIST; 32 | 33 | return 0; 34 | } 35 | 36 | int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) { 37 | return mkdir_safe_internal(path, mode, uid, gid, mkdir); 38 | } 39 | 40 | int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { 41 | const char *p, *e; 42 | int r; 43 | 44 | assert(path); 45 | 46 | if (prefix && !path_startswith(path, prefix)) 47 | return -ENOTDIR; 48 | 49 | /* return immediately if directory exists */ 50 | e = strrchr(path, '/'); 51 | if (!e) 52 | return -EINVAL; 53 | 54 | if (e == path) 55 | return 0; 56 | 57 | p = strndupa(path, e - path); 58 | r = is_dir(p, true); 59 | if (r > 0) 60 | return 0; 61 | if (r == 0) 62 | return -ENOTDIR; 63 | 64 | /* create every parent directory in the path, except the last component */ 65 | p = path + strspn(path, "/"); 66 | for (;;) { 67 | char t[strlen(path) + 1]; 68 | 69 | e = p + strcspn(p, "/"); 70 | p = e + strspn(e, "/"); 71 | 72 | /* Is this the last component? If so, then we're 73 | * done */ 74 | if (*p == 0) 75 | return 0; 76 | 77 | memcpy(t, path, e - path); 78 | t[e-path] = 0; 79 | 80 | if (prefix && path_startswith(prefix, t)) 81 | continue; 82 | 83 | r = _mkdir(t, mode); 84 | if (r < 0 && errno != EEXIST) 85 | return -errno; 86 | } 87 | } 88 | 89 | int mkdir_parents(const char *path, mode_t mode) { 90 | return mkdir_parents_internal(NULL, path, mode, mkdir); 91 | } 92 | 93 | int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { 94 | int r; 95 | 96 | /* Like mkdir -p */ 97 | 98 | r = mkdir_parents_internal(prefix, path, mode, _mkdir); 99 | if (r < 0) 100 | return r; 101 | 102 | r = _mkdir(path, mode); 103 | if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0)) 104 | return -errno; 105 | 106 | return 0; 107 | } 108 | 109 | int mkdir_p(const char *path, mode_t mode) { 110 | return mkdir_p_internal(NULL, path, mode, mkdir); 111 | } 112 | -------------------------------------------------------------------------------- /src/share/mkdir.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid); 8 | int mkdir_parents(const char *path, mode_t mode); 9 | int mkdir_p(const char *path, mode_t mode); 10 | 11 | /* mandatory access control(MAC) versions */ 12 | int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid); 13 | int mkdir_parents_label(const char *path, mode_t mode); 14 | int mkdir_p_label(const char *path, mode_t mode); 15 | 16 | /* internally used */ 17 | typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); 18 | int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir); 19 | int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); 20 | int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); 21 | -------------------------------------------------------------------------------- /src/share/network-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include "alloc-util.h" 4 | #include "fd-util.h" 5 | #include "network-util.h" 6 | #include "strv.h" 7 | 8 | bool network_is_online(void) { 9 | _cleanup_free_ char *state = NULL; 10 | int r; 11 | 12 | r = sd_network_get_operational_state(&state); 13 | if (r < 0) /* if we don't know anything, we consider the system online */ 14 | return true; 15 | 16 | if (STR_IN_SET(state, "routable", "degraded")) 17 | return true; 18 | 19 | return false; 20 | } 21 | -------------------------------------------------------------------------------- /src/share/network-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "sd-network.h" 6 | 7 | bool network_is_online(void); 8 | -------------------------------------------------------------------------------- /src/share/openssl-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static inline char *tls_error_string(int ssl_error, char *buf, size_t count) { 11 | assert(buf || count == 0); 12 | if (ssl_error == SSL_ERROR_SSL) 13 | ERR_error_string_n(ERR_get_error(), buf, count); 14 | else 15 | snprintf(buf, count, "SSL_get_error()=%d", ssl_error); 16 | return buf; 17 | } 18 | 19 | #define TLS_ERROR_BUFSIZE 256 20 | #define TLS_ERROR_STRING(error) \ 21 | tls_error_string((error), (char[TLS_ERROR_BUFSIZE]){}, TLS_ERROR_BUFSIZE) 22 | 23 | 24 | DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL); 25 | DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL); 26 | DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL); 27 | DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(void *, OPENSSL_free, NULL); 28 | -------------------------------------------------------------------------------- /src/share/parse-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "macro.h" 12 | 13 | #define MODE_INVALID ((mode_t) -1) 14 | 15 | int parse_boolean(const char *v) _pure_; 16 | int parse_ifindex(const char *s, int *ret); 17 | 18 | #define FORMAT_BYTES_MAX 8 19 | 20 | int safe_atou(const char *s, unsigned *ret_u); 21 | int safe_atoi(const char *s, int *ret_i); 22 | int safe_atollu(const char *s, unsigned long long *ret_u); 23 | int safe_atolli(const char *s, long long int *ret_i); 24 | 25 | static inline int safe_atou32(const char *s, uint32_t *ret_u) { 26 | assert_cc(sizeof(uint32_t) == sizeof(unsigned)); 27 | return safe_atou(s, (unsigned*) ret_u); 28 | } 29 | 30 | int parse_size(const char *t, uint64_t base, uint64_t *size); 31 | 32 | #if LONG_MAX == INT_MAX 33 | static inline int safe_atolu(const char *s, unsigned long *ret_u) { 34 | assert_cc(sizeof(unsigned long) == sizeof(unsigned)); 35 | return safe_atou(s, (unsigned*) ret_u); 36 | } 37 | static inline int safe_atoli(const char *s, long int *ret_u) { 38 | assert_cc(sizeof(long int) == sizeof(int)); 39 | return safe_atoi(s, (int*) ret_u); 40 | } 41 | #else 42 | static inline int safe_atolu(const char *s, unsigned long *ret_u) { 43 | assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); 44 | return safe_atollu(s, (unsigned long long*) ret_u); 45 | } 46 | static inline int safe_atoli(const char *s, long int *ret_u) { 47 | assert_cc(sizeof(long int) == sizeof(long long int)); 48 | return safe_atolli(s, (long long int*) ret_u); 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /src/share/path-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "macro.h" 10 | #include "time-util.h" 11 | 12 | #define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" 13 | #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" 14 | 15 | #ifdef HAVE_SPLIT_USR 16 | # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR 17 | #else 18 | # define DEFAULT_PATH DEFAULT_PATH_NORMAL 19 | #endif 20 | 21 | bool is_path(const char *p) _pure_; 22 | bool path_is_absolute(const char *p) _pure_; 23 | char* path_kill_slashes(char *path); 24 | char* path_startswith(const char *path, const char *prefix) _pure_; 25 | int path_compare(const char *a, const char *b) _pure_; 26 | bool path_equal(const char *a, const char *b) _pure_; 27 | 28 | /* Note: the search terminates on the first NULL item. */ 29 | #define PATH_IN_SET(p, ...) \ 30 | ({ \ 31 | char **s; \ 32 | bool _found = false; \ 33 | STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \ 34 | if (path_equal(p, *s)) { \ 35 | _found = true; \ 36 | break; \ 37 | } \ 38 | _found; \ 39 | }) 40 | 41 | char** path_strv_resolve(char **l, const char *prefix); 42 | char** path_strv_resolve_uniq(char **l, const char *prefix); 43 | 44 | /* Iterates through the path prefixes of the specified path, going up 45 | * the tree, to root. Also returns "" (and not "/"!) for the root 46 | * directory. Excludes the specified directory itself */ 47 | #define PATH_FOREACH_PREFIX(prefix, path) \ 48 | for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) 49 | 50 | /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ 51 | #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ 52 | for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) 53 | 54 | char *prefix_root(const char *root, const char *path); 55 | 56 | /* Similar to prefix_root(), but returns an alloca() buffer, or 57 | * possibly a const pointer into the path parameter */ 58 | #define prefix_roota(root, path) \ 59 | ({ \ 60 | const char* _path = (path), *_root = (root), *_ret; \ 61 | char *_p, *_n; \ 62 | size_t _l; \ 63 | while (_path[0] == '/' && _path[1] == '/') \ 64 | _path ++; \ 65 | if (isempty(_root) || path_equal(_root, "/")) \ 66 | _ret = _path; \ 67 | else { \ 68 | _l = strlen(_root) + 1 + strlen(_path) + 1; \ 69 | _n = alloca(_l); \ 70 | _p = stpcpy(_n, _root); \ 71 | while (_p > _n && _p[-1] == '/') \ 72 | _p--; \ 73 | if (_path[0] != '/') \ 74 | *(_p++) = '/'; \ 75 | strcpy(_p, _path); \ 76 | _ret = _n; \ 77 | } \ 78 | _ret; \ 79 | }) 80 | 81 | bool filename_is_valid(const char *p) _pure_; 82 | bool path_is_safe(const char *p) _pure_; 83 | 84 | char *file_in_same_dir(const char *path, const char *filename); 85 | 86 | bool hidden_or_backup_file(const char *filename) _pure_; 87 | -------------------------------------------------------------------------------- /src/share/proc-cmdline.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alloc-util.h" 8 | #include "extract-word.h" 9 | #include "fileio.h" 10 | #include "macro.h" 11 | #include "parse-util.h" 12 | #include "proc-cmdline.h" 13 | #include "process-util.h" 14 | #include "string-util.h" 15 | #include "util.h" 16 | #include "virt.h" 17 | 18 | int proc_cmdline(char **ret) { 19 | assert(ret); 20 | 21 | if (detect_container() > 0) 22 | return get_process_cmdline(1, 0, false, ret); 23 | else 24 | return read_one_line_file("/proc/cmdline", ret); 25 | } 26 | 27 | int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { 28 | _cleanup_free_ char *line = NULL; 29 | const char *p; 30 | int r; 31 | 32 | assert(parse_item); 33 | 34 | r = proc_cmdline(&line); 35 | if (r < 0) 36 | return r; 37 | 38 | p = line; 39 | for (;;) { 40 | _cleanup_free_ char *word = NULL; 41 | char *value = NULL; 42 | 43 | r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); 44 | if (r < 0) 45 | return r; 46 | if (r == 0) 47 | break; 48 | 49 | /* Filter out arguments that are intended only for the 50 | * initrd */ 51 | if (!in_initrd() && startswith(word, "rd.")) 52 | continue; 53 | 54 | value = strchr(word, '='); 55 | if (value) 56 | *(value++) = 0; 57 | 58 | r = parse_item(word, value); 59 | if (r < 0) 60 | return r; 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/share/proc-cmdline.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | int proc_cmdline(char **ret); 6 | int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); 7 | -------------------------------------------------------------------------------- /src/share/process-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "formats-util.h" 16 | #include "macro.h" 17 | 18 | 19 | #if !HAVE_GETTID 20 | static inline pid_t missing_gettid(void) { 21 | return (pid_t) syscall(__NR_gettid); 22 | } 23 | 24 | # define gettid missing_gettid 25 | #endif 26 | 27 | #define procfs_file_alloca(pid, field) \ 28 | ({ \ 29 | pid_t _pid_ = (pid); \ 30 | const char *_r_; \ 31 | if (_pid_ == 0) { \ 32 | _r_ = ("/proc/self/" field); \ 33 | } else { \ 34 | _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ 35 | sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ 36 | } \ 37 | _r_; \ 38 | }) 39 | 40 | int get_process_comm(pid_t pid, char **name); 41 | int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line); 42 | int get_process_uid(pid_t pid, uid_t *uid); 43 | int get_process_gid(pid_t pid, gid_t *gid); 44 | 45 | int getenv_for_pid(pid_t pid, const char *field, char **_value); 46 | 47 | void reset_cached_pid(void); 48 | 49 | pid_t getpid_cached(void); 50 | bool is_main_thread(void); 51 | 52 | const char *sigchld_code_to_string(int i) _const_; 53 | int sigchld_code_from_string(const char *s) _pure_; 54 | 55 | int sched_policy_to_string_alloc(int i, char **s); 56 | int sched_policy_from_string(const char *s); 57 | -------------------------------------------------------------------------------- /src/share/random-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef HAVE_SYS_AUXV_H 13 | #include 14 | #endif 15 | 16 | #if USE_SYS_RANDOM_H 17 | # include 18 | #else 19 | # include 20 | #endif 21 | 22 | #include "fd-util.h" 23 | #include "io-util.h" 24 | #include "process-util.h" 25 | #include "missing.h" 26 | #include "random-util.h" 27 | #include "time-util.h" 28 | 29 | int dev_urandom(void *p, size_t n) { 30 | static int have_syscall = -1; 31 | 32 | _cleanup_close_ int fd = -1; 33 | int r; 34 | 35 | /* Gathers some randomness from the kernel. This call will 36 | * never block, and will always return some data from the 37 | * kernel, regardless if the random pool is fully initialized 38 | * or not. It thus makes no guarantee for the quality of the 39 | * returned entropy, but is good enough for our usual usecases 40 | * of seeding the hash functions for hashtable */ 41 | 42 | /* Use the getrandom() syscall unless we know we don't have 43 | * it, or when the requested size is too large for it. */ 44 | if (have_syscall != 0 || (size_t) (int) n != n) { 45 | r = getrandom(p, n, GRND_NONBLOCK); 46 | if (r == (int) n) { 47 | have_syscall = true; 48 | return 0; 49 | } 50 | 51 | if (r < 0) { 52 | if (errno == ENOSYS) 53 | /* we lack the syscall, continue with 54 | * reading from /dev/urandom */ 55 | have_syscall = false; 56 | else if (errno == EAGAIN) 57 | /* not enough entropy for now. Let's 58 | * remember to use the syscall the 59 | * next time, again, but also read 60 | * from /dev/urandom for now, which 61 | * doesn't care about the current 62 | * amount of entropy. */ 63 | have_syscall = true; 64 | else 65 | return -errno; 66 | } else 67 | /* too short read? */ 68 | return -ENODATA; 69 | } 70 | 71 | fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); 72 | if (fd < 0) 73 | return errno == ENOENT ? -ENOSYS : -errno; 74 | 75 | return loop_read_exact(fd, p, n, true); 76 | } 77 | 78 | void initialize_srand(void) { 79 | static bool srand_called = false; 80 | unsigned x; 81 | #ifdef HAVE_SYS_AUXV_H 82 | void *auxv; 83 | #endif 84 | 85 | if (srand_called) 86 | return; 87 | 88 | #ifdef HAVE_SYS_AUXV_H 89 | /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the 90 | * pseudo-random generator. It's better than nothing... */ 91 | 92 | auxv = (void*) getauxval(AT_RANDOM); 93 | if (auxv) { 94 | assert_cc(sizeof(x) < 16); 95 | memcpy(&x, auxv, sizeof(x)); 96 | } else 97 | #endif 98 | x = 0; 99 | 100 | 101 | x ^= (unsigned) now(CLOCK_REALTIME); 102 | x ^= (unsigned) gettid(); 103 | 104 | srand(x); 105 | srand_called = true; 106 | } 107 | 108 | void random_bytes(void *p, size_t n) { 109 | uint8_t *q; 110 | int r; 111 | 112 | r = dev_urandom(p, n); 113 | if (r >= 0) 114 | return; 115 | 116 | /* If some idiot made /dev/urandom unavailable to us, he'll 117 | * get a PRNG instead. */ 118 | 119 | initialize_srand(); 120 | 121 | for (q = p; q < (uint8_t*) p + n; q ++) 122 | *q = rand(); 123 | } 124 | -------------------------------------------------------------------------------- /src/share/random-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | int dev_urandom(void *p, size_t n); 9 | void random_bytes(void *p, size_t n); 10 | void initialize_srand(void); 11 | 12 | static inline uint64_t random_u64(void) { 13 | uint64_t u; 14 | random_bytes(&u, sizeof(u)); 15 | return u; 16 | } 17 | 18 | static inline uint32_t random_u32(void) { 19 | uint32_t u; 20 | random_bytes(&u, sizeof(u)); 21 | return u; 22 | } 23 | -------------------------------------------------------------------------------- /src/share/ratelimit.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | 5 | #include "macro.h" 6 | #include "ratelimit.h" 7 | 8 | /* Modelled after Linux' lib/ratelimit.c by Dave Young 9 | * , which is licensed GPLv2. */ 10 | 11 | bool ratelimit_below(RateLimit *r) { 12 | usec_t ts; 13 | 14 | assert(r); 15 | 16 | if (!ratelimit_configured(r)) 17 | return true; 18 | 19 | ts = now(CLOCK_MONOTONIC); 20 | 21 | if (r->begin <= 0 || 22 | usec_sub_unsigned(ts, r->begin) > r->interval) { 23 | r->begin = ts; /* Start a new time window */ 24 | r->num = 1; /* Reset counter */ 25 | return true; 26 | } 27 | 28 | if (_unlikely_(r->num == UINT_MAX)) 29 | return false; 30 | 31 | r->num++; 32 | return r->num <= r->burst; 33 | } 34 | 35 | unsigned ratelimit_num_dropped(RateLimit *r) { 36 | assert(r); 37 | 38 | if (r->num == UINT_MAX) /* overflow, return as special case */ 39 | return UINT_MAX; 40 | 41 | return LESS_BY(r->num, r->burst); 42 | } 43 | 44 | usec_t ratelimit_end(const RateLimit *rl) { 45 | assert(rl); 46 | 47 | if (rl->begin == 0) 48 | return 0; 49 | 50 | return usec_add(rl->begin, rl->interval); 51 | } 52 | 53 | usec_t ratelimit_left(const RateLimit *rl) { 54 | assert(rl); 55 | 56 | if (rl->begin == 0) 57 | return 0; 58 | 59 | return usec_sub_unsigned(ratelimit_end(rl), now(CLOCK_MONOTONIC)); 60 | } 61 | -------------------------------------------------------------------------------- /src/share/ratelimit.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "time-util.h" 7 | 8 | typedef struct RateLimit { 9 | usec_t interval; /* Keep those two fields first so they can be initialized easily: */ 10 | unsigned burst; /* RateLimit rl = { INTERVAL, BURST }; */ 11 | unsigned num; 12 | usec_t begin; 13 | } RateLimit; 14 | 15 | #define RATELIMIT_OFF (const RateLimit) { .interval = USEC_INFINITY, .burst = UINT_MAX } 16 | 17 | static inline void ratelimit_reset(RateLimit *rl) { 18 | rl->num = rl->begin = 0; 19 | } 20 | 21 | static inline bool ratelimit_configured(const RateLimit *rl) { 22 | return rl->interval > 0 && rl->burst > 0; 23 | } 24 | 25 | bool ratelimit_below(RateLimit *r); 26 | 27 | unsigned ratelimit_num_dropped(RateLimit *r); 28 | 29 | usec_t ratelimit_end(const RateLimit *rl); 30 | usec_t ratelimit_left(const RateLimit *rl); 31 | -------------------------------------------------------------------------------- /src/share/sd-resolve.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ 2 | #ifndef foosdresolvehfoo 3 | #define foosdresolvehfoo 4 | 5 | /*** 6 | 7 | systemd is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | systemd is distributed in the hope that it will be useful, but 13 | WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with systemd; If not, see . 19 | ***/ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | _SD_BEGIN_DECLARATIONS; 30 | 31 | /* An opaque sd-resolve session structure */ 32 | typedef struct sd_resolve sd_resolve; 33 | 34 | /* An opaque sd-resolve query structure */ 35 | typedef struct sd_resolve_query sd_resolve_query; 36 | 37 | /* A callback on completion */ 38 | typedef int (*sd_resolve_getaddrinfo_handler_t)(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata); 39 | typedef int (*sd_resolve_getnameinfo_handler_t)(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata); 40 | 41 | enum { 42 | SD_RESOLVE_GET_HOST = 1 << 0, 43 | SD_RESOLVE_GET_SERVICE = 1 << 1, 44 | SD_RESOLVE_GET_BOTH = SD_RESOLVE_GET_HOST | SD_RESOLVE_GET_SERVICE, 45 | }; 46 | 47 | int sd_resolve_default(sd_resolve **ret); 48 | 49 | /* Allocate a new sd-resolve session. */ 50 | int sd_resolve_new(sd_resolve **ret); 51 | 52 | /* Free a sd-resolve session. This destroys all attached 53 | * sd_resolve_query objects automatically. */ 54 | sd_resolve* sd_resolve_unref(sd_resolve *resolve); 55 | sd_resolve* sd_resolve_ref(sd_resolve *resolve); 56 | 57 | /* Return the UNIX file descriptor to poll() for events on. Use this 58 | * function to integrate sd-resolve with your custom main loop. */ 59 | int sd_resolve_get_fd(sd_resolve *resolve); 60 | 61 | /* Return the poll() events (a combination of flags like POLLIN, 62 | * POLLOUT, ...) to check for. */ 63 | int sd_resolve_get_events(sd_resolve *resolve); 64 | 65 | /* Return the poll() timeout to pass. Returns (uint64_t) -1 as 66 | * timeout if no timeout is needed. */ 67 | int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *timeout_usec); 68 | 69 | /* Process pending responses. After this function is called, you can 70 | * get the next completed query object(s) using 71 | * sd_resolve_get_next(). */ 72 | int sd_resolve_process(sd_resolve *resolve); 73 | 74 | /* Wait for a resolve event to complete. */ 75 | int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec); 76 | 77 | int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid); 78 | 79 | int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority); 80 | int sd_resolve_detach_event(sd_resolve *resolve); 81 | sd_event *sd_resolve_get_event(sd_resolve *resolve); 82 | 83 | /* Issue a name-to-address query on the specified session. The 84 | * arguments are compatible with those of libc's 85 | * getaddrinfo(3). The function returns a new query object. When the 86 | * query is completed, you may retrieve the results using 87 | * sd_resolve_getaddrinfo_done(). */ 88 | int sd_resolve_getaddrinfo(sd_resolve *resolve, sd_resolve_query **q, const char *node, const char *service, const struct addrinfo *hints, sd_resolve_getaddrinfo_handler_t callback, void *userdata); 89 | 90 | /* Issue an address-to-name query on the specified session. The 91 | * arguments are compatible with those of libc's 92 | * getnameinfo(3). The function returns a new query object. When the 93 | * query is completed, you may retrieve the results using 94 | * sd_resolve_getnameinfo_done(). Set gethost (resp. getserv) to non-zero 95 | * if you want to query the hostname (resp. the service name). */ 96 | int sd_resolve_getnameinfo(sd_resolve *resolve, sd_resolve_query **q, const struct sockaddr *sa, socklen_t salen, int flags, uint64_t get, sd_resolve_getnameinfo_handler_t callback, void *userdata); 97 | 98 | sd_resolve_query *sd_resolve_query_ref(sd_resolve_query* q); 99 | sd_resolve_query *sd_resolve_query_unref(sd_resolve_query* q); 100 | 101 | /* Returns non-zero when the query operation specified by q has been completed. */ 102 | int sd_resolve_query_is_done(sd_resolve_query*q); 103 | 104 | void *sd_resolve_query_get_userdata(sd_resolve_query *q); 105 | void *sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata); 106 | 107 | sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q); 108 | 109 | _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_resolve, sd_resolve_unref); 110 | _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_resolve_query, sd_resolve_query_unref); 111 | 112 | _SD_END_DECLARATIONS; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/share/set.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include "extract-word.h" 6 | #include "hashmap.h" 7 | #include "macro.h" 8 | 9 | Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); 10 | #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) 11 | 12 | static inline Set *set_free(Set *s) { 13 | internal_hashmap_free(HASHMAP_BASE(s)); 14 | return NULL; 15 | } 16 | 17 | static inline Set *set_free_free(Set *s) { 18 | internal_hashmap_free_free(HASHMAP_BASE(s)); 19 | return NULL; 20 | } 21 | 22 | /* no set_free_free_free */ 23 | 24 | static inline Set *set_copy(Set *s) { 25 | return (Set*) internal_hashmap_copy(HASHMAP_BASE(s)); 26 | } 27 | 28 | int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); 29 | #define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) 30 | 31 | int set_put(Set *s, const void *key); 32 | /* no set_update */ 33 | /* no set_replace */ 34 | static inline void *set_get(Set *s, void *key) { 35 | return internal_hashmap_get(HASHMAP_BASE(s), key); 36 | } 37 | /* no set_get2 */ 38 | 39 | static inline bool set_contains(Set *s, const void *key) { 40 | return internal_hashmap_contains(HASHMAP_BASE(s), key); 41 | } 42 | 43 | static inline void *set_remove(Set *s, const void *key) { 44 | return internal_hashmap_remove(HASHMAP_BASE(s), key); 45 | } 46 | 47 | /* no set_remove2 */ 48 | /* no set_remove_value */ 49 | int set_remove_and_put(Set *s, const void *old_key, const void *new_key); 50 | /* no set_remove_and_replace */ 51 | int set_merge(Set *s, Set *other); 52 | 53 | static inline int set_reserve(Set *h, unsigned entries_add) { 54 | return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); 55 | } 56 | 57 | static inline int set_move(Set *s, Set *other) { 58 | return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); 59 | } 60 | 61 | static inline int set_move_one(Set *s, Set *other, const void *key) { 62 | return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key); 63 | } 64 | 65 | static inline unsigned set_size(Set *s) { 66 | return internal_hashmap_size(HASHMAP_BASE(s)); 67 | } 68 | 69 | static inline bool set_isempty(Set *s) { 70 | return set_size(s) == 0; 71 | } 72 | 73 | static inline unsigned set_buckets(Set *s) { 74 | return internal_hashmap_buckets(HASHMAP_BASE(s)); 75 | } 76 | 77 | bool set_iterate(Set *s, Iterator *i, void **value); 78 | 79 | static inline void set_clear(Set *s) { 80 | internal_hashmap_clear(HASHMAP_BASE(s)); 81 | } 82 | 83 | static inline void set_clear_free(Set *s) { 84 | internal_hashmap_clear_free(HASHMAP_BASE(s)); 85 | } 86 | 87 | /* no set_clear_free_free */ 88 | 89 | static inline void *set_steal_first(Set *s) { 90 | return internal_hashmap_steal_first(HASHMAP_BASE(s)); 91 | } 92 | 93 | /* no set_steal_first_key */ 94 | /* no set_first_key */ 95 | 96 | static inline void *set_first(Set *s) { 97 | return internal_hashmap_first(HASHMAP_BASE(s)); 98 | } 99 | 100 | /* no set_next */ 101 | 102 | static inline char **set_get_strv(Set *s) { 103 | return internal_hashmap_get_strv(HASHMAP_BASE(s)); 104 | } 105 | 106 | int set_consume(Set *s, void *value); 107 | int set_put_strdup(Set *s, const char *p); 108 | int set_put_strdupv(Set *s, char **l); 109 | int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); 110 | 111 | #define SET_FOREACH(e, s, i) \ 112 | for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) 113 | 114 | #define SET_FOREACH_MOVE(e, d, s) \ 115 | for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) 116 | 117 | DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); 118 | DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); 119 | 120 | #define _cleanup_set_free_ _cleanup_(set_freep) 121 | #define _cleanup_set_free_free_ _cleanup_(set_free_freep) 122 | -------------------------------------------------------------------------------- /src/share/signal-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "macro.h" 8 | #include "parse-util.h" 9 | #include "signal-util.h" 10 | #include "stdio-util.h" 11 | #include "string-table.h" 12 | #include "string-util.h" 13 | 14 | static int sigset_add_many_ap(sigset_t *ss, va_list ap) { 15 | int sig, r = 0; 16 | 17 | assert(ss); 18 | 19 | while ((sig = va_arg(ap, int)) >= 0) { 20 | 21 | if (sig == 0) 22 | continue; 23 | 24 | if (sigaddset(ss, sig) < 0) { 25 | if (r >= 0) 26 | r = -errno; 27 | } 28 | } 29 | 30 | return r; 31 | } 32 | 33 | int sigprocmask_many(int how, sigset_t *old, ...) { 34 | va_list ap; 35 | sigset_t ss; 36 | int r; 37 | 38 | if (sigemptyset(&ss) < 0) 39 | return -errno; 40 | 41 | va_start(ap, old); 42 | r = sigset_add_many_ap(&ss, ap); 43 | va_end(ap); 44 | 45 | if (r < 0) 46 | return r; 47 | 48 | if (sigprocmask(how, &ss, old) < 0) 49 | return -errno; 50 | 51 | return 0; 52 | } 53 | 54 | static const char *const __signal_table[] = { 55 | [SIGHUP] = "HUP", 56 | [SIGINT] = "INT", 57 | [SIGQUIT] = "QUIT", 58 | [SIGILL] = "ILL", 59 | [SIGTRAP] = "TRAP", 60 | [SIGABRT] = "ABRT", 61 | [SIGBUS] = "BUS", 62 | [SIGFPE] = "FPE", 63 | [SIGKILL] = "KILL", 64 | [SIGUSR1] = "USR1", 65 | [SIGSEGV] = "SEGV", 66 | [SIGUSR2] = "USR2", 67 | [SIGPIPE] = "PIPE", 68 | [SIGALRM] = "ALRM", 69 | [SIGTERM] = "TERM", 70 | #ifdef SIGSTKFLT 71 | [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ 72 | #endif 73 | [SIGCHLD] = "CHLD", 74 | [SIGCONT] = "CONT", 75 | [SIGSTOP] = "STOP", 76 | [SIGTSTP] = "TSTP", 77 | [SIGTTIN] = "TTIN", 78 | [SIGTTOU] = "TTOU", 79 | [SIGURG] = "URG", 80 | [SIGXCPU] = "XCPU", 81 | [SIGXFSZ] = "XFSZ", 82 | [SIGVTALRM] = "VTALRM", 83 | [SIGPROF] = "PROF", 84 | [SIGWINCH] = "WINCH", 85 | [SIGIO] = "IO", 86 | [SIGPWR] = "PWR", 87 | [SIGSYS] = "SYS" 88 | }; 89 | 90 | DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); 91 | 92 | const char *signal_to_string(int signo) { 93 | static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; 94 | const char *name; 95 | 96 | name = __signal_to_string(signo); 97 | if (name) 98 | return name; 99 | 100 | if (signo >= SIGRTMIN && signo <= SIGRTMAX) 101 | xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN); 102 | else 103 | xsprintf(buf, "%d", signo); 104 | 105 | return buf; 106 | } 107 | 108 | int signal_from_string(const char *s) { 109 | int signo; 110 | int offset = 0; 111 | unsigned u; 112 | 113 | signo = __signal_from_string(s); 114 | if (signo > 0) 115 | return signo; 116 | 117 | if (startswith(s, "RTMIN+")) { 118 | s += 6; 119 | offset = SIGRTMIN; 120 | } 121 | if (safe_atou(s, &u) >= 0) { 122 | signo = (int) u + offset; 123 | if (SIGNAL_VALID(signo)) 124 | return signo; 125 | } 126 | return -EINVAL; 127 | } 128 | 129 | void nop_signal_handler(int sig) { 130 | /* nothing here */ 131 | } 132 | -------------------------------------------------------------------------------- /src/share/signal-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "macro.h" 7 | 8 | int sigprocmask_many(int how, sigset_t *old, ...); 9 | 10 | const char *signal_to_string(int i) _const_; 11 | int signal_from_string(const char *s) _pure_; 12 | 13 | void nop_signal_handler(int sig); 14 | 15 | static inline void block_signals_reset(sigset_t *ss) { 16 | assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); 17 | } 18 | 19 | #define BLOCK_SIGNALS(...) \ 20 | _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ 21 | sigset_t t; \ 22 | assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ 23 | t; \ 24 | }) 25 | 26 | static inline bool SIGNAL_VALID(int signo) { 27 | return signo > 0 && signo < _NSIG; 28 | } 29 | -------------------------------------------------------------------------------- /src/share/siphash24.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct siphash { 9 | uint64_t v0; 10 | uint64_t v1; 11 | uint64_t v2; 12 | uint64_t v3; 13 | uint64_t padding; 14 | size_t inlen; 15 | }; 16 | 17 | void siphash24_init(struct siphash *state, const uint8_t k[16]); 18 | void siphash24_compress(const void *in, size_t inlen, struct siphash *state); 19 | #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) 20 | 21 | uint64_t siphash24_finalize(struct siphash *state); 22 | 23 | uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); 24 | -------------------------------------------------------------------------------- /src/share/socket-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "macro.h" 16 | #include "util.h" 17 | 18 | union sockaddr_union { 19 | struct sockaddr sa; 20 | struct sockaddr_in in; 21 | struct sockaddr_in6 in6; 22 | struct sockaddr_un un; 23 | struct sockaddr_nl nl; 24 | struct sockaddr_storage storage; 25 | struct sockaddr_ll ll; 26 | }; 27 | 28 | typedef struct SocketAddress { 29 | union sockaddr_union sockaddr; 30 | 31 | /* We store the size here explicitly due to the weird 32 | * sockaddr_un semantics for abstract sockets */ 33 | socklen_t size; 34 | 35 | /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ 36 | int type; 37 | 38 | /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ 39 | int protocol; 40 | } SocketAddress; 41 | 42 | typedef enum SocketAddressBindIPv6Only { 43 | SOCKET_ADDRESS_DEFAULT, 44 | SOCKET_ADDRESS_BOTH, 45 | SOCKET_ADDRESS_IPV6_ONLY, 46 | _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, 47 | _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 48 | } SocketAddressBindIPv6Only; 49 | 50 | #define socket_address_family(a) ((a)->sockaddr.sa.sa_family) 51 | 52 | int socket_address_parse(SocketAddress *a, const char *s); 53 | 54 | int socket_address_listen( 55 | const SocketAddress *a, 56 | int flags, 57 | int backlog, 58 | SocketAddressBindIPv6Only only, 59 | const char *bind_to_device, 60 | bool reuse_port, 61 | bool free_bind, 62 | bool transparent, 63 | mode_t directory_mode, 64 | mode_t socket_mode, 65 | const char *label); 66 | bool socket_ipv6_is_supported(void); 67 | 68 | int fd_inc_sndbuf(int fd, size_t n); 69 | int fd_inc_rcvbuf(int fd, size_t n); 70 | 71 | #define CMSG_FOREACH(cmsg, mh) \ 72 | for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) 73 | 74 | /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ 75 | #define SOCKADDR_UN_LEN(sa) \ 76 | ({ \ 77 | const struct sockaddr_un *_sa = &(sa); \ 78 | assert(_sa->sun_family == AF_UNIX); \ 79 | offsetof(struct sockaddr_un, sun_path) + \ 80 | (_sa->sun_path[0] == 0 ? \ 81 | 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ 82 | strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \ 83 | }) 84 | 85 | int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); 86 | 87 | static inline int setsockopt_int(int fd, int level, int optname, int value) { 88 | if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0) 89 | return -errno; 90 | 91 | return 0; 92 | } 93 | 94 | static inline int getsockopt_int(int fd, int level, int optname, int *ret) { 95 | int v; 96 | socklen_t sl = sizeof(v); 97 | 98 | if (getsockopt(fd, level, optname, &v, &sl) < 0) 99 | return negative_errno(); 100 | if (sl != sizeof(v)) 101 | return -EIO; 102 | 103 | *ret = v; 104 | return 0; 105 | } 106 | 107 | int fd_set_sndbuf(int fd, size_t n, bool increase); 108 | -------------------------------------------------------------------------------- /src/share/sparse-endian.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Josh Triplett 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to 5 | * deal in the Software without restriction, including without limitation the 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | */ 21 | #ifndef SPARSE_ENDIAN_H 22 | #define SPARSE_ENDIAN_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __CHECKER__ 29 | #define __bitwise __attribute__((bitwise)) 30 | #define __force __attribute__((force)) 31 | #else 32 | #define __bitwise 33 | #define __force 34 | #endif 35 | 36 | typedef uint16_t __bitwise le16_t; 37 | typedef uint16_t __bitwise be16_t; 38 | typedef uint32_t __bitwise le32_t; 39 | typedef uint32_t __bitwise be32_t; 40 | typedef uint64_t __bitwise le64_t; 41 | typedef uint64_t __bitwise be64_t; 42 | 43 | #undef htobe16 44 | #undef htole16 45 | #undef be16toh 46 | #undef le16toh 47 | #undef htobe32 48 | #undef htole32 49 | #undef be32toh 50 | #undef le32toh 51 | #undef htobe64 52 | #undef htole64 53 | #undef be64toh 54 | #undef le64toh 55 | 56 | #if __BYTE_ORDER == __LITTLE_ENDIAN 57 | #define bswap_16_on_le(x) __bswap_16(x) 58 | #define bswap_32_on_le(x) __bswap_32(x) 59 | #define bswap_64_on_le(x) __bswap_64(x) 60 | #define bswap_16_on_be(x) (x) 61 | #define bswap_32_on_be(x) (x) 62 | #define bswap_64_on_be(x) (x) 63 | #elif __BYTE_ORDER == __BIG_ENDIAN 64 | #define bswap_16_on_le(x) (x) 65 | #define bswap_32_on_le(x) (x) 66 | #define bswap_64_on_le(x) (x) 67 | #define bswap_16_on_be(x) __bswap_16(x) 68 | #define bswap_32_on_be(x) __bswap_32(x) 69 | #define bswap_64_on_be(x) __bswap_64(x) 70 | #endif 71 | 72 | static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } 73 | static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } 74 | static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } 75 | 76 | static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } 77 | static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } 78 | static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } 79 | 80 | static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } 81 | static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } 82 | static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } 83 | 84 | static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } 85 | static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } 86 | static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } 87 | 88 | #endif /* SPARSE_ENDIAN_H */ 89 | -------------------------------------------------------------------------------- /src/share/stat-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "dirent-util.h" 13 | #include "fd-util.h" 14 | #include "macro.h" 15 | #include "missing.h" 16 | #include "stat-util.h" 17 | #include "string-util.h" 18 | 19 | int is_dir(const char* path, bool follow) { 20 | struct stat st; 21 | int r; 22 | 23 | assert(path); 24 | 25 | if (follow) 26 | r = stat(path, &st); 27 | else 28 | r = lstat(path, &st); 29 | if (r < 0) 30 | return -errno; 31 | 32 | return !!S_ISDIR(st.st_mode); 33 | } 34 | 35 | bool null_or_empty(const struct stat *st) { 36 | assert(st); 37 | 38 | if (S_ISREG(st->st_mode) && st->st_size <= 0) 39 | return true; 40 | 41 | /* We don't want to hardcode the major/minor of /dev/null, 42 | * hence we do a simpler "is this a device node?" check. */ 43 | 44 | if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) 45 | return true; 46 | 47 | return false; 48 | } 49 | 50 | int files_same(const char *filea, const char *fileb) { 51 | struct stat a, b; 52 | 53 | assert(filea); 54 | assert(fileb); 55 | 56 | if (stat(filea, &a) < 0) 57 | return -errno; 58 | 59 | if (stat(fileb, &b) < 0) 60 | return -errno; 61 | 62 | return a.st_dev == b.st_dev && 63 | a.st_ino == b.st_ino; 64 | } 65 | 66 | bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { 67 | assert(s); 68 | assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type)); 69 | 70 | return F_TYPE_EQUAL(s->f_type, magic_value); 71 | } 72 | 73 | bool is_temporary_fs(const struct statfs *s) { 74 | return is_fs_type(s, TMPFS_MAGIC) || 75 | is_fs_type(s, RAMFS_MAGIC); 76 | } 77 | -------------------------------------------------------------------------------- /src/share/stat-util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "macro.h" 12 | 13 | int is_dir(const char *path, bool follow); 14 | 15 | bool null_or_empty(const struct stat *st) _pure_; 16 | 17 | int files_same(const char *filea, const char *fileb); 18 | 19 | /* The .f_type field of struct statfs is really weird defined on 20 | * different archs. Let's give its type a name. */ 21 | typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t; 22 | 23 | bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value); 24 | 25 | bool is_temporary_fs(const struct statfs *s) _pure_; 26 | 27 | /* Because statfs.t_type can be int on some architectures, we have to cast 28 | * the const magic to the type, otherwise the compiler warns about 29 | * signed/unsigned comparison, because the magic can be 32 bit unsigned. 30 | */ 31 | #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) 32 | -------------------------------------------------------------------------------- /src/share/stdio-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | 12 | #define xsprintf(buf, fmt, ...) \ 13 | assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") 14 | 15 | 16 | #define VA_FORMAT_ADVANCE(format, ap) \ 17 | do { \ 18 | int _argtypes[128]; \ 19 | size_t _i, _k; \ 20 | _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ 21 | assert(_k < ELEMENTSOF(_argtypes)); \ 22 | for (_i = 0; _i < _k; _i++) { \ 23 | if (_argtypes[_i] & PA_FLAG_PTR) { \ 24 | (void) va_arg(ap, void*); \ 25 | continue; \ 26 | } \ 27 | \ 28 | switch (_argtypes[_i]) { \ 29 | case PA_INT: \ 30 | case PA_INT|PA_FLAG_SHORT: \ 31 | case PA_CHAR: \ 32 | (void) va_arg(ap, int); \ 33 | break; \ 34 | case PA_INT|PA_FLAG_LONG: \ 35 | (void) va_arg(ap, long int); \ 36 | break; \ 37 | case PA_INT|PA_FLAG_LONG_LONG: \ 38 | (void) va_arg(ap, long long int); \ 39 | break; \ 40 | case PA_WCHAR: \ 41 | (void) va_arg(ap, wchar_t); \ 42 | break; \ 43 | case PA_WSTRING: \ 44 | case PA_STRING: \ 45 | case PA_POINTER: \ 46 | (void) va_arg(ap, void*); \ 47 | break; \ 48 | case PA_FLOAT: \ 49 | case PA_DOUBLE: \ 50 | (void) va_arg(ap, double); \ 51 | break; \ 52 | case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ 53 | (void) va_arg(ap, long double); \ 54 | break; \ 55 | default: \ 56 | assert_not_reached("Unknown format string argument."); \ 57 | } \ 58 | } \ 59 | } while (false) 60 | -------------------------------------------------------------------------------- /src/share/string-table.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include "string-table.h" 4 | #include "string-util.h" 5 | 6 | ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { 7 | size_t i; 8 | 9 | if (!key) 10 | return -1; 11 | 12 | for (i = 0; i < len; ++i) 13 | if (streq_ptr(table[i], key)) 14 | return (ssize_t) i; 15 | 16 | return -1; 17 | } 18 | -------------------------------------------------------------------------------- /src/share/string-table.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "macro.h" 12 | #include "parse-util.h" 13 | #include "string-util.h" 14 | 15 | ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); 16 | 17 | /* For basic lookup tables with strictly enumerated entries */ 18 | #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 19 | scope const char *name##_to_string(type i) { \ 20 | if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ 21 | return NULL; \ 22 | return name##_table[i]; \ 23 | } 24 | 25 | #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ 26 | scope type name##_from_string(const char *s) { \ 27 | return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ 28 | } 29 | 30 | #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ 31 | scope type name##_from_string(const char *s) { \ 32 | int b; \ 33 | if (!s) \ 34 | return -1; \ 35 | b = parse_boolean(s); \ 36 | if (b == 0) \ 37 | return (type) 0; \ 38 | else if (b > 0) \ 39 | return yes; \ 40 | return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ 41 | } 42 | 43 | #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \ 44 | scope int name##_to_string_alloc(type i, char **str) { \ 45 | char *s; \ 46 | if (i < 0 || i > max) \ 47 | return -ERANGE; \ 48 | if (i < (type) ELEMENTSOF(name##_table)) { \ 49 | s = strdup(name##_table[i]); \ 50 | if (!s) \ 51 | return -ENOMEM; \ 52 | } else { \ 53 | if (asprintf(&s, "%i", i) < 0) \ 54 | return -ENOMEM; \ 55 | } \ 56 | *str = s; \ 57 | return 0; \ 58 | } 59 | 60 | #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \ 61 | type name##_from_string(const char *s) { \ 62 | type i; \ 63 | unsigned u = 0; \ 64 | if (!s) \ 65 | return (type) -1; \ 66 | for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ 67 | if (streq_ptr(name##_table[i], s)) \ 68 | return i; \ 69 | if (safe_atou(s, &u) >= 0 && u <= max) \ 70 | return (type) u; \ 71 | return (type) -1; \ 72 | } \ 73 | 74 | 75 | #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ 76 | _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 77 | _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ 78 | struct __useless_struct_to_allow_trailing_semicolon__ 79 | 80 | #define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ 81 | _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ 82 | _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ 83 | struct __useless_struct_to_allow_trailing_semicolon__ 84 | 85 | #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) 86 | #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) 87 | #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) 88 | #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) 89 | 90 | #define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) 91 | 92 | /* For string conversions where numbers are also acceptable */ 93 | #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ 94 | _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ 95 | _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ 96 | struct __useless_struct_to_allow_trailing_semicolon__ 97 | 98 | #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ 99 | _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) 100 | #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ 101 | _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) 102 | -------------------------------------------------------------------------------- /src/share/string-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | 12 | /* What is interpreted as whitespace? */ 13 | #define WHITESPACE " \t\n\r" 14 | #define NEWLINE "\n\r" 15 | #define QUOTES "\"\'" 16 | #define COMMENTS "#;" 17 | #define GLOB_CHARS "*?[" 18 | #define DIGITS "0123456789" 19 | #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" 20 | #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 21 | #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS 22 | #define ALPHANUMERICAL LETTERS DIGITS 23 | #define HEXDIGITS DIGITS "abcdefABCDEF" 24 | 25 | typedef char sd_char; 26 | 27 | #define streq(a,b) (strcmp((a),(b)) == 0) 28 | #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) 29 | #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) 30 | #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) 31 | 32 | int strcmp_ptr(const char *a, const char *b) _pure_; 33 | 34 | static inline bool streq_ptr(const char *a, const char *b) { 35 | return strcmp_ptr(a, b) == 0; 36 | } 37 | 38 | static inline const char* strempty(const char *s) { 39 | return s ? s : ""; 40 | } 41 | 42 | static inline const char* strnull(const char *s) { 43 | return s ? s : "(null)"; 44 | } 45 | 46 | static inline const char *strna(const char *s) { 47 | return s ? s : "n/a"; 48 | } 49 | 50 | static inline bool isempty(const char *p) { 51 | return !p || !p[0]; 52 | } 53 | 54 | static inline const char *empty_to_null(const char *p) { 55 | return isempty(p) ? NULL : p; 56 | } 57 | 58 | static inline char *startswith(const char *s, const char *prefix) { 59 | size_t l; 60 | 61 | l = strlen(prefix); 62 | if (strncmp(s, prefix, l) == 0) 63 | return (char*) s + l; 64 | 65 | return NULL; 66 | } 67 | 68 | static inline char *startswith_no_case(const char *s, const char *prefix) { 69 | size_t l; 70 | 71 | l = strlen(prefix); 72 | if (strncasecmp(s, prefix, l) == 0) 73 | return (char*) s + l; 74 | 75 | return NULL; 76 | } 77 | 78 | char *endswith(const char *s, const char *postfix) _pure_; 79 | char *endswith_no_case(const char *s, const char *postfix) _pure_; 80 | 81 | char *first_word(const char *s, const char *word) _pure_; 82 | 83 | const char* split(const char **state, size_t *l, const char *separator, bool quoted); 84 | 85 | #define FOREACH_WORD(word, length, s, state) \ 86 | _FOREACH_WORD(word, length, s, WHITESPACE, false, state) 87 | 88 | #define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ 89 | _FOREACH_WORD(word, length, s, separator, false, state) 90 | 91 | #define FOREACH_WORD_QUOTED(word, length, s, state) \ 92 | _FOREACH_WORD(word, length, s, WHITESPACE, true, state) 93 | 94 | #define _FOREACH_WORD(word, length, s, separator, quoted, state) \ 95 | for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) 96 | 97 | char *strappend(const char *s, const char *suffix); 98 | char *strnappend(const char *s, const char *suffix, size_t length); 99 | 100 | char *strjoin(const char *x, ...) _sentinel_; 101 | 102 | #define strjoina(a, ...) \ 103 | ({ \ 104 | const char *_appendees_[] = { a, __VA_ARGS__ }; \ 105 | char *_d_, *_p_; \ 106 | int _len_ = 0; \ 107 | unsigned _i_; \ 108 | for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ 109 | _len_ += strlen(_appendees_[_i_]); \ 110 | _p_ = _d_ = alloca(_len_ + 1); \ 111 | for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ 112 | _p_ = stpcpy(_p_, _appendees_[_i_]); \ 113 | *_p_ = 0; \ 114 | _d_; \ 115 | }) 116 | 117 | static inline bool ascii_isdigit(sd_char a) { 118 | /* A pure ASCII, locale independent version of isdigit() */ 119 | return a >= '0' && a <= '9'; 120 | } 121 | 122 | static inline bool ascii_isalpha(sd_char a) { 123 | /* A pure ASCII, locale independent version of isalpha() */ 124 | return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); 125 | } 126 | 127 | char *strstrip(char *s); 128 | char *truncate_nl(char *s); 129 | 130 | char ascii_tolower(char x); 131 | 132 | bool nulstr_contains(const char*nulstr, const char *needle); 133 | 134 | void* memory_erase(void *p, size_t l); 135 | char *string_erase(char *x); 136 | 137 | char *string_free_erase(char *s); 138 | DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase); 139 | #define _cleanup_string_free_erase_ _cleanup_(string_free_erasep) 140 | -------------------------------------------------------------------------------- /src/share/strv.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "alloc-util.h" 11 | #include "extract-word.h" 12 | #include "macro.h" 13 | #include "util.h" 14 | 15 | char *strv_find(char **l, const char *name) _pure_; 16 | char *strv_find_prefix(char **l, const char *name) _pure_; 17 | 18 | char **strv_free(char **l); 19 | DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); 20 | #define _cleanup_strv_free_ _cleanup_(strv_freep) 21 | 22 | char **strv_free_erase(char **l); 23 | DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); 24 | #define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) 25 | 26 | void strv_clear(char **l); 27 | 28 | char **strv_copy(char * const *l); 29 | unsigned strv_length(char * const *l) _pure_; 30 | 31 | int strv_extend(char ***l, const char *value); 32 | int strv_push(char ***l, char *value); 33 | int strv_consume(char ***l, char *value); 34 | 35 | char **strv_remove(char **l, const char *s); 36 | char **strv_uniq(char **l); 37 | 38 | #define strv_contains(l, s) (!!strv_find((l), (s))) 39 | 40 | char **strv_new(const char *x, ...) _sentinel_; 41 | char **strv_new_ap(const char *x, va_list ap); 42 | 43 | #define STRV_IGNORE ((const char *) -1) 44 | 45 | static inline const char* STRV_IFNOTNULL(const char *x) { 46 | return x ? x : STRV_IGNORE; 47 | } 48 | 49 | static inline bool strv_isempty(char * const *l) { 50 | return !l || !*l; 51 | } 52 | 53 | char **strv_split(const char *s, const char *separator); 54 | 55 | char **strv_split_nulstr(const char *s); 56 | 57 | #define STRV_FOREACH(s, l) \ 58 | for ((s) = (l); (s) && *(s); (s)++) 59 | 60 | #define STRV_FOREACH_BACKWARDS(s, l) \ 61 | STRV_FOREACH(s, l) \ 62 | ; \ 63 | for ((s)--; (l) && ((s) >= (l)); (s)--) 64 | 65 | #define STRV_FOREACH_PAIR(x, y, l) \ 66 | for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) 67 | 68 | #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) 69 | 70 | #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) 71 | -------------------------------------------------------------------------------- /src/share/syslog-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | 6 | #include "hexdecoct.h" 7 | #include "macro.h" 8 | #include "string-table.h" 9 | #include "syslog-util.h" 10 | 11 | int syslog_parse_priority(const char **p, int *priority, bool with_facility) { 12 | int a = 0, b = 0, c = 0; 13 | int k; 14 | 15 | assert(p); 16 | assert(*p); 17 | assert(priority); 18 | 19 | if ((*p)[0] != '<') 20 | return 0; 21 | 22 | if (!strchr(*p, '>')) 23 | return 0; 24 | 25 | if ((*p)[2] == '>') { 26 | c = undecchar((*p)[1]); 27 | k = 3; 28 | } else if ((*p)[3] == '>') { 29 | b = undecchar((*p)[1]); 30 | c = undecchar((*p)[2]); 31 | k = 4; 32 | } else if ((*p)[4] == '>') { 33 | a = undecchar((*p)[1]); 34 | b = undecchar((*p)[2]); 35 | c = undecchar((*p)[3]); 36 | k = 5; 37 | } else 38 | return 0; 39 | 40 | if (a < 0 || b < 0 || c < 0 || 41 | (!with_facility && (a || b || c > 7))) 42 | return 0; 43 | 44 | if (with_facility) 45 | *priority = a*100 + b*10 + c; 46 | else 47 | *priority = (*priority & LOG_FACMASK) | c; 48 | 49 | *p += k; 50 | return 1; 51 | } 52 | 53 | static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { 54 | [LOG_FAC(LOG_KERN)] = "kern", 55 | [LOG_FAC(LOG_USER)] = "user", 56 | [LOG_FAC(LOG_MAIL)] = "mail", 57 | [LOG_FAC(LOG_DAEMON)] = "daemon", 58 | [LOG_FAC(LOG_AUTH)] = "auth", 59 | [LOG_FAC(LOG_SYSLOG)] = "syslog", 60 | [LOG_FAC(LOG_LPR)] = "lpr", 61 | [LOG_FAC(LOG_NEWS)] = "news", 62 | [LOG_FAC(LOG_UUCP)] = "uucp", 63 | [LOG_FAC(LOG_CRON)] = "cron", 64 | [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", 65 | [LOG_FAC(LOG_FTP)] = "ftp", 66 | [LOG_FAC(LOG_LOCAL0)] = "local0", 67 | [LOG_FAC(LOG_LOCAL1)] = "local1", 68 | [LOG_FAC(LOG_LOCAL2)] = "local2", 69 | [LOG_FAC(LOG_LOCAL3)] = "local3", 70 | [LOG_FAC(LOG_LOCAL4)] = "local4", 71 | [LOG_FAC(LOG_LOCAL5)] = "local5", 72 | [LOG_FAC(LOG_LOCAL6)] = "local6", 73 | [LOG_FAC(LOG_LOCAL7)] = "local7" 74 | }; 75 | 76 | DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); 77 | 78 | bool log_facility_unshifted_is_valid(int facility) { 79 | return facility >= 0 && facility <= LOG_FAC(~0); 80 | } 81 | 82 | static const char *const log_level_table[] = { 83 | [LOG_EMERG] = "emerg", 84 | [LOG_ALERT] = "alert", 85 | [LOG_CRIT] = "crit", 86 | [LOG_ERR] = "err", 87 | [LOG_WARNING] = "warning", 88 | [LOG_NOTICE] = "notice", 89 | [LOG_INFO] = "info", 90 | [LOG_DEBUG] = "debug" 91 | }; 92 | 93 | DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); 94 | 95 | bool log_level_is_valid(int level) { 96 | return level >= 0 && level <= LOG_DEBUG; 97 | } 98 | -------------------------------------------------------------------------------- /src/share/syslog-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | int log_facility_unshifted_to_string_alloc(int i, char **s); 8 | int log_facility_unshifted_from_string(const char *s); 9 | bool log_facility_unshifted_is_valid(int faciliy); 10 | 11 | int log_level_to_string_alloc(int i, char **s); 12 | int log_level_from_string(const char *s); 13 | bool log_level_is_valid(int level); 14 | 15 | int syslog_parse_priority(const char **p, int *priority, bool with_facility); 16 | -------------------------------------------------------------------------------- /src/share/terminal-util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "alloc-util.h" 25 | #include "fd-util.h" 26 | #include "fileio.h" 27 | #include "fs-util.h" 28 | #include "io-util.h" 29 | #include "log.h" 30 | #include "macro.h" 31 | #include "parse-util.h" 32 | #include "process-util.h" 33 | #include "socket-util.h" 34 | #include "stat-util.h" 35 | #include "string-util.h" 36 | #include "strv.h" 37 | #include "terminal-util.h" 38 | #include "time-util.h" 39 | #include "util.h" 40 | 41 | static volatile unsigned cached_columns = 0; 42 | static volatile unsigned cached_lines = 0; 43 | 44 | int open_terminal(const char *name, int mode) { 45 | int fd, r; 46 | unsigned c = 0; 47 | 48 | /* 49 | * If a TTY is in the process of being closed opening it might 50 | * cause EIO. This is horribly awful, but unlikely to be 51 | * changed in the kernel. Hence we work around this problem by 52 | * retrying a couple of times. 53 | * 54 | * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 55 | */ 56 | 57 | if (mode & O_CREAT) 58 | return -EINVAL; 59 | 60 | for (;;) { 61 | fd = open(name, mode, 0); 62 | if (fd >= 0) 63 | break; 64 | 65 | if (errno != EIO) 66 | return -errno; 67 | 68 | /* Max 1s in total */ 69 | if (c >= 20) 70 | return -errno; 71 | 72 | usleep(50 * USEC_PER_MSEC); 73 | c++; 74 | } 75 | 76 | r = isatty(fd); 77 | if (r < 0) { 78 | safe_close(fd); 79 | return -errno; 80 | } 81 | 82 | if (!r) { 83 | safe_close(fd); 84 | return -ENOTTY; 85 | } 86 | 87 | return fd; 88 | } 89 | 90 | bool on_tty(void) { 91 | static int cached_on_tty = -1; 92 | 93 | if (_unlikely_(cached_on_tty < 0)) 94 | cached_on_tty = isatty(STDOUT_FILENO) > 0; 95 | 96 | return cached_on_tty; 97 | } 98 | 99 | int get_ctty_devnr(pid_t pid, dev_t *d) { 100 | int r; 101 | _cleanup_free_ char *line = NULL; 102 | const char *p; 103 | unsigned long ttynr; 104 | 105 | assert(pid >= 0); 106 | 107 | p = procfs_file_alloca(pid, "stat"); 108 | r = read_one_line_file(p, &line); 109 | if (r < 0) 110 | return r; 111 | 112 | p = strrchr(line, ')'); 113 | if (!p) 114 | return -EIO; 115 | 116 | p++; 117 | 118 | if (sscanf(p, " " 119 | "%*c " /* state */ 120 | "%*d " /* ppid */ 121 | "%*d " /* pgrp */ 122 | "%*d " /* session */ 123 | "%lu ", /* ttynr */ 124 | &ttynr) != 1) 125 | return -EIO; 126 | 127 | if (major(ttynr) == 0 && minor(ttynr) == 0) 128 | return -ENXIO; 129 | 130 | if (d) 131 | *d = (dev_t) ttynr; 132 | 133 | return 0; 134 | } 135 | 136 | bool terminal_is_dumb(void) { 137 | const char *e; 138 | 139 | if (!on_tty()) 140 | return true; 141 | 142 | e = getenv("TERM"); 143 | if (!e) 144 | return true; 145 | 146 | return streq(e, "dumb"); 147 | } 148 | 149 | bool colors_enabled(void) { 150 | static int enabled = -1; 151 | 152 | if (_unlikely_(enabled < 0)) { 153 | const char *colors; 154 | 155 | colors = getenv("SYSTEMD_COLORS"); 156 | if (colors) 157 | enabled = parse_boolean(colors) != 0; 158 | else 159 | enabled = !terminal_is_dumb(); 160 | } 161 | 162 | return enabled; 163 | } 164 | -------------------------------------------------------------------------------- /src/share/terminal-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | #include "time-util.h" 12 | 13 | #define ANSI_RED "\x1B[0;31m" 14 | #define ANSI_GREEN "\x1B[0;32m" 15 | #define ANSI_UNDERLINE "\x1B[0;4m" 16 | #define ANSI_HIGHLIGHT "\x1B[0;1;39m" 17 | #define ANSI_HIGHLIGHT_RED "\x1B[0;1;31m" 18 | #define ANSI_HIGHLIGHT_GREEN "\x1B[0;1;32m" 19 | #define ANSI_HIGHLIGHT_YELLOW "\x1B[0;1;33m" 20 | #define ANSI_HIGHLIGHT_BLUE "\x1B[0;1;34m" 21 | #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" 22 | #define ANSI_NORMAL "\x1B[0m" 23 | 24 | #define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" 25 | 26 | /* Set cursor to top left corner and clear screen */ 27 | #define ANSI_HOME_CLEAR "\x1B[H\x1B[2J" 28 | 29 | int open_terminal(const char *name, int mode); 30 | 31 | bool on_tty(void); 32 | bool terminal_is_dumb(void); 33 | bool colors_enabled(void); 34 | 35 | static inline const char *ansi_underline(void) { 36 | return colors_enabled() ? ANSI_UNDERLINE : ""; 37 | } 38 | 39 | static inline const char *ansi_highlight(void) { 40 | return colors_enabled() ? ANSI_HIGHLIGHT : ""; 41 | } 42 | 43 | static inline const char *ansi_highlight_underline(void) { 44 | return colors_enabled() ? ANSI_HIGHLIGHT_UNDERLINE : ""; 45 | } 46 | 47 | static inline const char *ansi_highlight_red(void) { 48 | return colors_enabled() ? ANSI_HIGHLIGHT_RED : ""; 49 | } 50 | 51 | static inline const char *ansi_highlight_green(void) { 52 | return colors_enabled() ? ANSI_HIGHLIGHT_GREEN : ""; 53 | } 54 | 55 | static inline const char *ansi_highlight_yellow(void) { 56 | return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW : ""; 57 | } 58 | 59 | static inline const char *ansi_highlight_blue(void) { 60 | return colors_enabled() ? ANSI_HIGHLIGHT_BLUE : ""; 61 | } 62 | 63 | static inline const char *ansi_normal(void) { 64 | return colors_enabled() ? ANSI_NORMAL : ""; 65 | } 66 | 67 | int get_ctty_devnr(pid_t pid, dev_t *d); 68 | -------------------------------------------------------------------------------- /src/share/time-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef uint64_t usec_t; 13 | typedef uint64_t nsec_t; 14 | 15 | #define NSEC_FMT "%" PRIu64 16 | #define USEC_FMT "%" PRIu64 17 | 18 | #include "macro.h" 19 | 20 | typedef struct dual_timestamp { 21 | usec_t realtime; 22 | usec_t monotonic; 23 | } dual_timestamp; 24 | 25 | typedef struct triple_timestamp { 26 | usec_t realtime; 27 | usec_t monotonic; 28 | usec_t boottime; 29 | } triple_timestamp; 30 | 31 | #define USEC_INFINITY ((usec_t) -1) 32 | #define NSEC_INFINITY ((nsec_t) -1) 33 | 34 | #define MSEC_PER_SEC 1000ULL 35 | #define USEC_PER_SEC ((usec_t) 1000000ULL) 36 | #define USEC_PER_MSEC ((usec_t) 1000ULL) 37 | #define NSEC_PER_SEC ((nsec_t) 1000000000ULL) 38 | #define NSEC_PER_MSEC ((nsec_t) 1000000ULL) 39 | #define NSEC_PER_USEC ((nsec_t) 1000ULL) 40 | 41 | #define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) 42 | #define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) 43 | #define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) 44 | #define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) 45 | #define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) 46 | #define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) 47 | #define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) 48 | #define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) 49 | #define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) 50 | #define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) 51 | #define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) 52 | #define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) 53 | 54 | #define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ 55 | #define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */ 56 | #define FORMAT_TIMESTAMP_RELATIVE_MAX 256 57 | #define FORMAT_TIMESPAN_MAX 64 58 | 59 | #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) 60 | 61 | #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {}) 62 | #define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {}) 63 | 64 | usec_t now(clockid_t clock); 65 | 66 | usec_t timespec_load(const struct timespec *ts) _pure_; 67 | struct timespec *timespec_store(struct timespec *ts, usec_t u); 68 | 69 | struct timeval *timeval_store(struct timeval *tv, usec_t u); 70 | 71 | #define xstrftime(buf, fmt, tm) \ 72 | assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ 73 | "xstrftime: " #buf "[] must be big enough") 74 | 75 | static inline usec_t usec_add(usec_t a, usec_t b) { 76 | /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, 77 | * and doesn't overflow. */ 78 | 79 | if (a > USEC_INFINITY - b) /* overflow check */ 80 | return USEC_INFINITY; 81 | 82 | return a + b; 83 | } 84 | 85 | static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) { 86 | if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */ 87 | return USEC_INFINITY; 88 | if (timestamp < delta) 89 | return 0; 90 | 91 | return timestamp - delta; 92 | } 93 | 94 | static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { 95 | if (delta == INT64_MIN) { /* prevent overflow */ 96 | assert_cc(-(INT64_MIN + 1) == INT64_MAX); 97 | assert_cc(USEC_INFINITY > INT64_MAX); 98 | return usec_add(timestamp, (usec_t) INT64_MAX + 1); 99 | } 100 | if (delta < 0) 101 | return usec_add(timestamp, (usec_t) (-delta)); 102 | 103 | return usec_sub_unsigned(timestamp, (usec_t) delta); 104 | } 105 | 106 | int parse_sec(const char *t, usec_t *ret); 107 | int parse_time(const char *t, usec_t *ret, usec_t default_unit); 108 | 109 | static inline bool timestamp_is_set(usec_t timestamp) { 110 | return timestamp > 0 && timestamp != USEC_INFINITY; 111 | } 112 | -------------------------------------------------------------------------------- /src/share/umask-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "macro.h" 10 | 11 | static inline void umaskp(mode_t *u) { 12 | umask(*u); 13 | } 14 | 15 | #define _cleanup_umask_ _cleanup_(umaskp) 16 | 17 | struct _umask_struct_ { 18 | mode_t mask; 19 | bool quit; 20 | }; 21 | 22 | static inline void _reset_umask_(struct _umask_struct_ *s) { 23 | umask(s->mask); 24 | }; 25 | 26 | #define RUN_WITH_UMASK(mask) \ 27 | for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ 28 | !_saved_umask_.quit ; \ 29 | _saved_umask_.quit = true) 30 | -------------------------------------------------------------------------------- /src/share/unaligned.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | /* BE */ 9 | 10 | static inline uint16_t unaligned_read_be16(const void *_u) { 11 | const uint8_t *u = _u; 12 | 13 | return (((uint16_t) u[0]) << 8) | 14 | ((uint16_t) u[1]); 15 | } 16 | 17 | static inline uint32_t unaligned_read_be32(const void *_u) { 18 | const uint8_t *u = _u; 19 | 20 | return (((uint32_t) unaligned_read_be16(u)) << 16) | 21 | ((uint32_t) unaligned_read_be16(u + 2)); 22 | } 23 | 24 | static inline uint64_t unaligned_read_be64(const void *_u) { 25 | const uint8_t *u = _u; 26 | 27 | return (((uint64_t) unaligned_read_be32(u)) << 32) | 28 | ((uint64_t) unaligned_read_be32(u + 4)); 29 | } 30 | 31 | static inline void unaligned_write_be16(void *_u, uint16_t a) { 32 | uint8_t *u = _u; 33 | 34 | u[0] = (uint8_t) (a >> 8); 35 | u[1] = (uint8_t) a; 36 | } 37 | 38 | static inline void unaligned_write_be32(void *_u, uint32_t a) { 39 | uint8_t *u = _u; 40 | 41 | unaligned_write_be16(u, (uint16_t) (a >> 16)); 42 | unaligned_write_be16(u + 2, (uint16_t) a); 43 | } 44 | 45 | static inline void unaligned_write_be64(void *_u, uint64_t a) { 46 | uint8_t *u = _u; 47 | 48 | unaligned_write_be32(u, (uint32_t) (a >> 32)); 49 | unaligned_write_be32(u + 4, (uint32_t) a); 50 | } 51 | 52 | /* LE */ 53 | 54 | static inline uint16_t unaligned_read_le16(const void *_u) { 55 | const uint8_t *u = _u; 56 | 57 | return (((uint16_t) u[1]) << 8) | 58 | ((uint16_t) u[0]); 59 | } 60 | 61 | static inline uint32_t unaligned_read_le32(const void *_u) { 62 | const uint8_t *u = _u; 63 | 64 | return (((uint32_t) unaligned_read_le16(u + 2)) << 16) | 65 | ((uint32_t) unaligned_read_le16(u)); 66 | } 67 | 68 | static inline uint64_t unaligned_read_le64(const void *_u) { 69 | const uint8_t *u = _u; 70 | 71 | return (((uint64_t) unaligned_read_le32(u + 4)) << 32) | 72 | ((uint64_t) unaligned_read_le32(u)); 73 | } 74 | 75 | static inline void unaligned_write_le16(void *_u, uint16_t a) { 76 | uint8_t *u = _u; 77 | 78 | u[0] = (uint8_t) a; 79 | u[1] = (uint8_t) (a >> 8); 80 | } 81 | 82 | static inline void unaligned_write_le32(void *_u, uint32_t a) { 83 | uint8_t *u = _u; 84 | 85 | unaligned_write_le16(u, (uint16_t) a); 86 | unaligned_write_le16(u + 2, (uint16_t) (a >> 16)); 87 | } 88 | 89 | static inline void unaligned_write_le64(void *_u, uint64_t a) { 90 | uint8_t *u = _u; 91 | 92 | unaligned_write_le32(u, (uint32_t) a); 93 | unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); 94 | } 95 | 96 | #if __BYTE_ORDER == __BIG_ENDIAN 97 | #define unaligned_read_ne16 unaligned_read_be16 98 | #define unaligned_read_ne32 unaligned_read_be32 99 | #define unaligned_read_ne64 unaligned_read_be64 100 | 101 | #define unaligned_write_ne16 unaligned_write_be16 102 | #define unaligned_write_ne32 unaligned_write_be32 103 | #define unaligned_write_ne64 unaligned_write_be64 104 | #else 105 | #define unaligned_read_ne16 unaligned_read_le16 106 | #define unaligned_read_ne32 unaligned_read_le32 107 | #define unaligned_read_ne64 unaligned_read_le64 108 | 109 | #define unaligned_write_ne16 unaligned_write_le16 110 | #define unaligned_write_ne32 unaligned_write_le32 111 | #define unaligned_write_ne64 unaligned_write_le64 112 | #endif 113 | -------------------------------------------------------------------------------- /src/share/user-util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | bool uid_is_valid(uid_t uid); 10 | 11 | static inline bool gid_is_valid(gid_t gid) { 12 | return uid_is_valid((uid_t) gid); 13 | } 14 | 15 | int parse_uid(const char *s, uid_t* ret_uid); 16 | 17 | static inline int parse_gid(const char *s, gid_t *ret_gid) { 18 | return parse_uid(s, (uid_t*) ret_gid); 19 | } 20 | 21 | char* getlogname_malloc(void); 22 | char* getusername_malloc(void); 23 | 24 | int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); 25 | int get_group_creds(const char **groupname, gid_t *gid); 26 | 27 | char* uid_to_name(uid_t uid); 28 | char* gid_to_name(gid_t gid); 29 | 30 | 31 | int reset_uid_gid(void); 32 | 33 | #define UID_INVALID ((uid_t) -1) 34 | #define GID_INVALID ((gid_t) -1) 35 | 36 | /* The following macros add 1 when converting things, since UID 0 is a 37 | * valid UID, while the pointer NULL is special */ 38 | #define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) 39 | #define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) 40 | 41 | #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) 42 | #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) 43 | 44 | static inline bool userns_supported(void) { 45 | return access("/proc/self/uid_map", F_OK) >= 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/share/utf8.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "macro.h" 11 | #include "missing.h" 12 | 13 | #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" 14 | #define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf" 15 | 16 | bool unichar_is_valid(char32_t c); 17 | 18 | const char *utf8_is_valid(const char *s) _pure_; 19 | char *ascii_is_valid(const char *s) _pure_; 20 | 21 | char *utf8_escape_invalid(const char *s); 22 | 23 | size_t utf8_encode_unichar(char *out_utf8, char32_t g); 24 | 25 | int utf8_encoded_valid_unichar(const char *str); 26 | int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar); 27 | 28 | static inline bool utf16_is_surrogate(char16_t c) { 29 | return (0xd800 <= c && c <= 0xdfff); 30 | } 31 | 32 | static inline bool utf16_is_trailing_surrogate(char16_t c) { 33 | return (0xdc00 <= c && c <= 0xdfff); 34 | } 35 | 36 | static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) { 37 | return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; 38 | } 39 | -------------------------------------------------------------------------------- /src/share/util.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "alloc-util.h" 21 | #include "build.h" 22 | #include "def.h" 23 | #include "dirent-util.h" 24 | #include "fd-util.h" 25 | #include "fileio.h" 26 | #include "formats-util.h" 27 | #include "log.h" 28 | #include "macro.h" 29 | #include "missing.h" 30 | #include "parse-util.h" 31 | #include "path-util.h" 32 | #include "process-util.h" 33 | #include "set.h" 34 | #include "signal-util.h" 35 | #include "stat-util.h" 36 | #include "string-util.h" 37 | #include "strv.h" 38 | #include "time-util.h" 39 | #include "umask-util.h" 40 | #include "user-util.h" 41 | #include "util.h" 42 | 43 | /* Put this test here for a lack of better place */ 44 | assert_cc(EAGAIN == EWOULDBLOCK); 45 | 46 | int saved_argc = 0; 47 | char **saved_argv = NULL; 48 | static int saved_in_initrd = -1; 49 | 50 | size_t page_size(void) { 51 | static thread_local size_t pgsz = 0; 52 | long r; 53 | 54 | if (_likely_(pgsz > 0)) 55 | return pgsz; 56 | 57 | r = sysconf(_SC_PAGESIZE); 58 | assert(r > 0); 59 | 60 | pgsz = (size_t) r; 61 | return pgsz; 62 | } 63 | 64 | int prot_from_flags(int flags) { 65 | 66 | switch (flags & O_ACCMODE) { 67 | 68 | case O_RDONLY: 69 | return PROT_READ; 70 | 71 | case O_WRONLY: 72 | return PROT_WRITE; 73 | 74 | case O_RDWR: 75 | return PROT_READ|PROT_WRITE; 76 | 77 | default: 78 | return -EINVAL; 79 | } 80 | } 81 | 82 | bool in_initrd(void) { 83 | struct statfs s; 84 | 85 | if (saved_in_initrd >= 0) 86 | return saved_in_initrd; 87 | 88 | /* We make two checks here: 89 | * 90 | * 1. the flag file /etc/initrd-release must exist 91 | * 2. the root file system must be a memory file system 92 | * 93 | * The second check is extra paranoia, since misdetecting an 94 | * initrd can have bad bad consequences due the initrd 95 | * emptying when transititioning to the main systemd. 96 | */ 97 | 98 | saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && 99 | statfs("/", &s) >= 0 && 100 | is_temporary_fs(&s); 101 | 102 | return saved_in_initrd; 103 | } 104 | 105 | void in_initrd_force(bool value) { 106 | saved_in_initrd = value; 107 | } 108 | 109 | int version(void) { 110 | puts(PACKAGE_STRING "\n" 111 | SYSTEMD_FEATURES); 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/share/util.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "formats-util.h" 28 | #include "macro.h" 29 | #include "missing.h" 30 | #include "time-util.h" 31 | 32 | size_t page_size(void) _pure_; 33 | #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) 34 | 35 | static inline const char* yes_no(bool b) { 36 | return b ? "yes" : "no"; 37 | } 38 | 39 | static inline const char* true_false(bool b) { 40 | return b ? "true" : "false"; 41 | } 42 | 43 | static inline const char* one_zero(bool b) { 44 | return b ? "1" : "0"; 45 | } 46 | 47 | #define NULSTR_FOREACH(i, l) \ 48 | for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) 49 | 50 | #define NULSTR_FOREACH_PAIR(i, j, l) \ 51 | for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) 52 | 53 | extern int saved_argc; 54 | extern char **saved_argv; 55 | 56 | int prot_from_flags(int flags) _const_; 57 | 58 | bool in_initrd(void); 59 | void in_initrd_force(bool value); 60 | 61 | /** 62 | * Normal qsort requires base to be nonnull. Here were require 63 | * that only if nmemb > 0. 64 | */ 65 | static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { 66 | if (nmemb <= 1) 67 | return; 68 | 69 | assert(base); 70 | qsort(base, nmemb, size, compar); 71 | } 72 | 73 | #define memzero(x, l) \ 74 | ({ \ 75 | size_t _l_ = (l); \ 76 | _l_ > 0 ? memset((x), 0, _l_) : (x); \ 77 | }) 78 | 79 | 80 | static inline void *mempset(void *s, int c, size_t n) { 81 | memset(s, c, n); 82 | return (uint8_t*)s + n; 83 | } 84 | 85 | static inline void _reset_errno_(int *saved_errno) { 86 | errno = *saved_errno; 87 | } 88 | 89 | #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno 90 | 91 | static inline int negative_errno(void) { 92 | /* This helper should be used to shut up gcc if you know 'errno' is 93 | * negative. Instead of "return -errno;", use "return negative_errno();" 94 | * It will suppress bogus gcc warnings in case it assumes 'errno' might 95 | * be 0 and thus the caller's error-handling might not be triggered. */ 96 | assert_return(errno > 0, -EINVAL); 97 | return -errno; 98 | } 99 | 100 | static inline int RET_NERRNO(int ret) { 101 | 102 | /* Helper to wrap system calls in to make them return negative errno errors. This brings system call 103 | * error handling in sync with how we usually handle errors in our own code, i.e. with immediate 104 | * returning of negative errno. Usage is like this: 105 | * 106 | * … 107 | * r = RET_NERRNO(unlink(t)); 108 | * … 109 | * 110 | * or 111 | * 112 | * … 113 | * fd = RET_NERRNO(open("/etc/fstab", O_RDONLY|O_CLOEXEC)); 114 | * … 115 | */ 116 | 117 | if (ret < 0) 118 | return negative_errno(); 119 | 120 | return ret; 121 | } 122 | 123 | static inline unsigned u64log2(uint64_t n) { 124 | #if __SIZEOF_LONG_LONG__ == 8 125 | return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; 126 | #else 127 | #error "Wut?" 128 | #endif 129 | } 130 | 131 | static inline unsigned u32ctz(uint32_t n) { 132 | #if __SIZEOF_INT__ == 4 133 | return __builtin_ctz(n); 134 | #else 135 | #error "Wut?" 136 | #endif 137 | } 138 | 139 | static inline unsigned log2i(int x) { 140 | assert(x > 0); 141 | 142 | return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1; 143 | } 144 | 145 | static inline unsigned log2u(unsigned x) { 146 | assert(x > 0); 147 | 148 | return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; 149 | } 150 | 151 | static inline unsigned log2u_round_up(unsigned x) { 152 | assert(x > 0); 153 | 154 | if (x == 1) 155 | return 0; 156 | 157 | return log2u(x - 1) + 1; 158 | } 159 | 160 | int version(void); 161 | -------------------------------------------------------------------------------- /src/share/virt.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "alloc-util.h" 10 | #include "dirent-util.h" 11 | #include "fd-util.h" 12 | #include "fileio.h" 13 | #include "macro.h" 14 | #include "process-util.h" 15 | #include "stat-util.h" 16 | #include "string-table.h" 17 | #include "string-util.h" 18 | #include "virt.h" 19 | 20 | int detect_container(void) { 21 | 22 | static const struct { 23 | const char *value; 24 | int id; 25 | } value_table[] = { 26 | { "lxc", VIRTUALIZATION_LXC }, 27 | { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT }, 28 | { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN }, 29 | { "docker", VIRTUALIZATION_DOCKER }, 30 | { "rkt", VIRTUALIZATION_RKT }, 31 | }; 32 | 33 | static thread_local int cached_found = _VIRTUALIZATION_INVALID; 34 | _cleanup_free_ char *m = NULL; 35 | const char *e = NULL; 36 | unsigned j; 37 | int r; 38 | 39 | if (cached_found >= 0) 40 | return cached_found; 41 | 42 | /* /proc/vz exists in container and outside of the container, 43 | * /proc/bc only outside of the container. */ 44 | if (access("/proc/vz", F_OK) >= 0 && 45 | access("/proc/bc", F_OK) < 0) { 46 | r = VIRTUALIZATION_OPENVZ; 47 | goto finish; 48 | } 49 | 50 | if (getpid() == 1) { 51 | /* If we are PID 1 we can just check our own 52 | * environment variable */ 53 | 54 | e = getenv("container"); 55 | if (isempty(e)) { 56 | r = VIRTUALIZATION_NONE; 57 | goto finish; 58 | } 59 | } else { 60 | 61 | /* Otherwise, PID 1 dropped this information into a 62 | * file in /run. This is better than accessing 63 | * /proc/1/environ, since we don't need CAP_SYS_PTRACE 64 | * for that. */ 65 | 66 | r = read_one_line_file("/run/systemd/container", &m); 67 | if (r == -ENOENT) { 68 | 69 | /* Fallback for cases where PID 1 was not 70 | * systemd (for example, cases where 71 | * init=/bin/sh is used. */ 72 | 73 | r = getenv_for_pid(1, "container", &m); 74 | if (r <= 0) { 75 | 76 | /* If that didn't work, give up, 77 | * assume no container manager. 78 | * 79 | * Note: This means we still cannot 80 | * detect containers if init=/bin/sh 81 | * is passed but privileges dropped, 82 | * as /proc/1/environ is only readable 83 | * with privileges. */ 84 | 85 | r = VIRTUALIZATION_NONE; 86 | goto finish; 87 | } 88 | } 89 | if (r < 0) 90 | return r; 91 | 92 | e = m; 93 | } 94 | 95 | for (j = 0; j < ELEMENTSOF(value_table); j++) 96 | if (streq(e, value_table[j].value)) { 97 | r = value_table[j].id; 98 | goto finish; 99 | } 100 | 101 | r = VIRTUALIZATION_CONTAINER_OTHER; 102 | 103 | finish: 104 | log_debug("Found container virtualization %s", virtualization_to_string(r)); 105 | cached_found = r; 106 | return r; 107 | } 108 | 109 | int running_in_chroot(void) { 110 | int ret; 111 | 112 | ret = files_same("/proc/1/root", "/"); 113 | if (ret < 0) 114 | return ret; 115 | 116 | return ret == 0; 117 | } 118 | 119 | static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { 120 | [VIRTUALIZATION_NONE] = "none", 121 | [VIRTUALIZATION_KVM] = "kvm", 122 | [VIRTUALIZATION_QEMU] = "qemu", 123 | [VIRTUALIZATION_BOCHS] = "bochs", 124 | [VIRTUALIZATION_XEN] = "xen", 125 | [VIRTUALIZATION_UML] = "uml", 126 | [VIRTUALIZATION_VMWARE] = "vmware", 127 | [VIRTUALIZATION_ORACLE] = "oracle", 128 | [VIRTUALIZATION_MICROSOFT] = "microsoft", 129 | [VIRTUALIZATION_ZVM] = "zvm", 130 | [VIRTUALIZATION_PARALLELS] = "parallels", 131 | [VIRTUALIZATION_VM_OTHER] = "vm-other", 132 | 133 | [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn", 134 | [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt", 135 | [VIRTUALIZATION_LXC] = "lxc", 136 | [VIRTUALIZATION_OPENVZ] = "openvz", 137 | [VIRTUALIZATION_DOCKER] = "docker", 138 | [VIRTUALIZATION_RKT] = "rkt", 139 | [VIRTUALIZATION_CONTAINER_OTHER] = "container-other", 140 | }; 141 | 142 | DEFINE_STRING_TABLE_LOOKUP(virtualization, int); 143 | -------------------------------------------------------------------------------- /src/share/virt.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | #include "macro.h" 8 | 9 | enum { 10 | VIRTUALIZATION_NONE = 0, 11 | 12 | VIRTUALIZATION_VM_FIRST, 13 | VIRTUALIZATION_KVM = VIRTUALIZATION_VM_FIRST, 14 | VIRTUALIZATION_QEMU, 15 | VIRTUALIZATION_BOCHS, 16 | VIRTUALIZATION_XEN, 17 | VIRTUALIZATION_UML, 18 | VIRTUALIZATION_VMWARE, 19 | VIRTUALIZATION_ORACLE, 20 | VIRTUALIZATION_MICROSOFT, 21 | VIRTUALIZATION_ZVM, 22 | VIRTUALIZATION_PARALLELS, 23 | VIRTUALIZATION_VM_OTHER, 24 | VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER, 25 | 26 | VIRTUALIZATION_CONTAINER_FIRST, 27 | VIRTUALIZATION_SYSTEMD_NSPAWN = VIRTUALIZATION_CONTAINER_FIRST, 28 | VIRTUALIZATION_LXC_LIBVIRT, 29 | VIRTUALIZATION_LXC, 30 | VIRTUALIZATION_OPENVZ, 31 | VIRTUALIZATION_DOCKER, 32 | VIRTUALIZATION_RKT, 33 | VIRTUALIZATION_CONTAINER_OTHER, 34 | VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER, 35 | 36 | _VIRTUALIZATION_MAX, 37 | _VIRTUALIZATION_INVALID = -1 38 | }; 39 | 40 | static inline bool VIRTUALIZATION_IS_VM(int x) { 41 | return x >= VIRTUALIZATION_VM_FIRST && x <= VIRTUALIZATION_VM_LAST; 42 | } 43 | 44 | static inline bool VIRTUALIZATION_IS_CONTAINER(int x) { 45 | return x >= VIRTUALIZATION_CONTAINER_FIRST && x <= VIRTUALIZATION_CONTAINER_LAST; 46 | } 47 | 48 | int detect_vm(void); 49 | int detect_container(void); 50 | 51 | int running_in_chroot(void); 52 | 53 | const char *virtualization_to_string(int v) _const_; 54 | int virtualization_from_string(const char *s) _pure_; 55 | -------------------------------------------------------------------------------- /systemd-netlogd.spec: -------------------------------------------------------------------------------- 1 | Name: systemd-netlogd 2 | Version: 1.4 3 | Release: 1%{?dist} 4 | Summary: Forwards messages from the journal to other hosts over the network using syslog format RFC 5424 5 | 6 | License: GPLv2 and LGPL-2.1+ and CC0 7 | URL: https://github.com/systemd/systemd-netlogd 8 | Source0: %{URL}/archive/v%{version}.tar.gz 9 | 10 | BuildRequires: gperf 11 | BuildRequires: libcap-devel 12 | BuildRequires: pkg-config 13 | BuildRequires: systemd-devel 14 | BuildRequires: python3-sphinx 15 | BuildRequires: meson >= 0.43 16 | 17 | %description 18 | Forwards messages from the journal to other hosts over the network 19 | using the Syslog Protocol (RFC 5424 and RFC 3339). It can be configured 20 | to send messages to both unicast and multicast addresses. systemd-netlogd 21 | runs with own user systemd-journal-netlog. Starts sending logs when network 22 | is up and stops sending as soon as network is down (uses sd-network). 23 | It reads from journal and forwards to network one by one. It does not 24 | use any extra disk space. systemd-netlogd supports UDP, TCP, TLS and DTLS 25 | (Datagram Transport Layer Security RFC 6012). 26 | 27 | BuildRequires: gcc 28 | BuildRequires: libcap-devel 29 | BuildRequires: docbook-style-xsl 30 | BuildRequires: gperf 31 | BuildRequires: python3-devel 32 | BuildRequires: python3-lxml 33 | BuildRequires: git 34 | BuildRequires: meson >= 0.43 35 | BuildRequires: systemd-devel 36 | BuildRequires: openssl-devel 37 | 38 | %prep 39 | %autosetup 40 | rm -rf build && mkdir build 41 | 42 | %build 43 | pushd build 44 | meson .. 45 | ninja-build -v 46 | popd 47 | 48 | %install 49 | pushd build 50 | DESTDIR=%{buildroot} ninja-build -v install 51 | popd 52 | 53 | %files 54 | %{_sysconfdir}/systemd/system/netlogd.conf 55 | %{_sysconfdir}/systemd/system/systemd-netlogd.service 56 | /lib/systemd/systemd-netlogd 57 | %{_mandir}/man8/systemd-netlogd.8* 58 | 59 | %changelog 60 | * Tue May 14 2024 Susant Sahani - 1.4 61 | - Initial spec 62 | -------------------------------------------------------------------------------- /units/.gitignore: -------------------------------------------------------------------------------- 1 | /systemd-netlogd.service 2 | -------------------------------------------------------------------------------- /units/meson.build: -------------------------------------------------------------------------------- 1 | systemd_netlogd_conf = configure_file( 2 | input : 'systemd-netlogd.service.in', 3 | output : 'systemd-netlogd.service', 4 | configuration : conf) 5 | install_data(systemd_netlogd_conf, 6 | install_dir : get_option('prefix') / 'system') 7 | -------------------------------------------------------------------------------- /units/systemd-netlogd.service.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-2.1-or-later 2 | # This file is part of systemd. 3 | 4 | [Unit] 5 | Description=Journal Syslog Unicast and Multicast Daemon 6 | Documentation=man:systemd-netlogd(8) 7 | After=network.target 8 | 9 | [Service] 10 | ExecStart=@PKGPREFIX@/systemd-netlogd 11 | WatchdogSec=20min 12 | 13 | # hardening 14 | LockPersonality=yes 15 | MemoryDenyWriteExecute=yes 16 | PrivateTmp=yes 17 | PrivateDevices=yes 18 | ProtectClock=yes 19 | ProtectControlGroups=yes 20 | ProtectHome=yes 21 | ProtectHostname=yes 22 | ProtectKernelLogs=yes 23 | ProtectKernelModules=yes 24 | ProtectKernelTunables=yes 25 | ProtectProc=invisible 26 | ProtectSystem=strict 27 | StateDirectory=systemd/journal-netlogd 28 | SystemCallArchitectures=native 29 | 30 | [Install] 31 | WantedBy=multi-user.target 32 | --------------------------------------------------------------------------------