diff options
95 files changed, 2794 insertions, 1953 deletions
diff --git a/Makefile.am b/Makefile.am index c2973c0a67..003308e580 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5167,41 +5167,48 @@ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ src/network/networkd-link.h \ + src/network/networkd-link.c \ src/network/networkd-netdev.h \ - src/network/networkd-netdev-tunnel.h \ - src/network/networkd-netdev-veth.h \ - src/network/networkd-netdev-vxlan.h \ - src/network/networkd-netdev-vlan.h \ - src/network/networkd-netdev-macvlan.h \ - src/network/networkd-netdev-ipvlan.h \ - src/network/networkd-netdev-dummy.h \ - src/network/networkd-netdev-tuntap.h \ - src/network/networkd-netdev-bond.h \ - src/network/networkd-netdev-bridge.h \ src/network/networkd-netdev.c \ + src/network/networkd-netdev-tunnel.h \ src/network/networkd-netdev-tunnel.c \ + src/network/networkd-netdev-veth.h \ src/network/networkd-netdev-veth.c \ + src/network/networkd-netdev-vxlan.h \ src/network/networkd-netdev-vxlan.c \ + src/network/networkd-netdev-vlan.h \ src/network/networkd-netdev-vlan.c \ + src/network/networkd-netdev-macvlan.h \ src/network/networkd-netdev-macvlan.c \ + src/network/networkd-netdev-ipvlan.h \ src/network/networkd-netdev-ipvlan.c \ + src/network/networkd-netdev-dummy.h \ src/network/networkd-netdev-dummy.c \ + src/network/networkd-netdev-tuntap.h \ src/network/networkd-netdev-tuntap.c \ + src/network/networkd-netdev-bond.h \ src/network/networkd-netdev-bond.c \ + src/network/networkd-netdev-bridge.h \ src/network/networkd-netdev-bridge.c \ - src/network/networkd-link.c \ src/network/networkd-link-bus.c \ src/network/networkd-ipv4ll.c \ src/network/networkd-dhcp4.c \ src/network/networkd-dhcp6.c \ + src/network/networkd-network.h \ src/network/networkd-network.c \ src/network/networkd-network-bus.c \ + src/network/networkd-address.h \ src/network/networkd-address.c \ + src/network/networkd-route.h \ src/network/networkd-route.c \ src/network/networkd-manager.c \ src/network/networkd-manager-bus.c \ + src/network/networkd-fdb.h \ src/network/networkd-fdb.c \ - src/network/networkd-address-pool.c + src/network/networkd-address-pool.h \ + src/network/networkd-address-pool.c \ + src/network/networkd-util.h \ + src/network/networkd-util.c nodist_libnetworkd_core_la_SOURCES = \ src/network/networkd-network-gperf.c \ @@ -32,10 +32,6 @@ Features: * nspawn should optionally support receiving WATCHDOG=1 messages from its payload PID 1... -* introduce "machinectl shell" that is like systemd-run -M foo /bin/bash -t but also adds PAMName=login - -* allow loging into host with "machinectl login". - * consider throwing a warning if a service declares it wants to be "Before=" a .device unit. * "systemctl edit" should know a mode to create a new unit file @@ -65,10 +61,6 @@ Features: * logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins -* change to KillMode=mixed by default - -* introduce argv0contains= - * invent a better systemd-run scheme for naming scopes, that works with remoting * add journalctl -H that talks via ssh to a remote peer and passes through binary logs data @@ -256,8 +248,6 @@ Features: * figure out when we can use the coarse timers -* sd-resolve: drop res_query wrapping, people should call via the bus to resolved instead - * add "systemctl start -v foobar.service" that shows logs of a service while the start command runs. This is non-trivial to do without races though, since we should flush out all journal messages before @@ -330,18 +320,15 @@ Features: - expose in the API the following bits: - option 15, domain name and/or option 119, search list - option 12, host name and/or option 81, fqdn - - option 100, 101, timezone - option 123, 144, geolocation - option 252, configure http proxy (PAC/wpad) - - networkd's dhcp server should transparently pass on the DNS and - NTP server list it got from user configuration and its dhcp client - to clients. It should also pass on its own timezone information. - provide a way to define a per-network interface default metric value for all routes to it. possibly a second default for DHCP routes. - allow Name= to be specified repeatedly in the [Match] section. Maybe also support Name=foo*|bar*|baz ? - duplicate address check for static IPs (like ARPCHECK in network-scripts) - allow DUID/IAID to be customized, see issue #394. + - networkd: whenever uplink info changes, make DHCP server send out FORCERENEW * resolved: - put networkd events and rtnl events at a higher priority, so that @@ -473,7 +460,6 @@ Features: * sd-bus: - EBADSLT handling - - change argv list matching logic - GetAllProperties() on a non-existing object does not result in a failure currently - kdbus: process fd=-1 for incoming msgs - port to sd-resolve for connecting to TCP dbus servers @@ -895,7 +881,6 @@ Features: * dhcp: - figure out how much we can increase Maximum Message Size - - export timezone information - support RFC4702 (pass FQDN) * dhcp6: diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb index d992e65c68..1e0a38e7f7 100644 --- a/hwdb/70-mouse.hwdb +++ b/hwdb/70-mouse.hwdb @@ -173,6 +173,10 @@ mouse:usb:v093ap2510:name:PIXART USB OPTICAL MOUSE: mouse:usb:v17efp6019:name:Lenovo Optical USB Mouse: MOUSE_DPI=1000@125 +# Lenovo M-U0025-O +mouse:usb:v17efp6019:name:Logitech Lenovo USB Optical Mouse: + MOUSE_DPI=1000@166 + # ThinkPad USB Laser Mouse mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse: MOUSE_DPI=1200@125 @@ -181,6 +185,13 @@ mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse: mouse:usb:v17efp6050:name:Lenovo Precision USB Mouse: MOUSE_DPI=1200@127 +# Lenovo MOBGUL +mouse:usb:v17efp601d:name:Primax Lenovo Laser Mouse: +# Lenovo MOBGULA +mouse:usb:v17efp6045:name:Lenovo USB Laser Mouse: + MOUSE_DPI=1600@125 + + ########################################## # Logitech ########################################## @@ -236,7 +247,7 @@ mouse:usb:v046dpc01e:name:Logitech USB-PS/2 Optical Mouse: # Logitech, Inc. RX 250 Optical Mouse mouse:usb:v046dpc050:name:Logitech USB-PS/2 Optical Mouse: - MOUSE_DPI=800@142 + MOUSE_DPI=1000@142 # Logitech Wireless Mouse M185 mouse:usb:v046dp4008:name:Logitech M185: diff --git a/man/networkctl.xml b/man/networkctl.xml index 388afbed93..46dab58d61 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -87,6 +87,7 @@ <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> + <xi:include href="standard-options.xml" xpointer="no-legend" /> <xi:include href="standard-options.xml" xpointer="no-pager" /> </variablelist> diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index d4b041a1f9..e4bc22f278 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -64,10 +64,10 @@ regular intervals (by default every 1s), similar in style to <citerefentry project='man-pages'><refentrytitle>top</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> - <para>If <command>systemd-cgtop</command> is not connected to a tty, no - column headers are printed and the default is to only run one iteration. - The <varname>--iterations</varname> argument, if given, is still honored. - This mode is suitable for scripting.</para> + <para>If <command>systemd-cgtop</command> is not connected to a + tty, no column headers are printed and the default is to only run + one iteration. The <varname>--iterations=</varname> argument, if + given, is honored. This mode is suitable for scripting.</para> <para>Resource usage is only accounted for control groups in the relevant hierarchy, i.e. CPU usage is only accounted for control @@ -104,6 +104,7 @@ <variablelist> <varlistentry> <term><option>-p</option></term> + <term><option>--order=path</option></term> <listitem><para>Order by control group path name.</para></listitem> @@ -111,25 +112,28 @@ <varlistentry> <term><option>-t</option></term> + <term><option>--order=tasks</option></term> - <listitem><para>Order by number of tasks in control group - (i.e. threads and processes).</para></listitem> + <listitem><para>Order by number of processes in control group.</para></listitem> </varlistentry> <varlistentry> <term><option>-c</option></term> + <term><option>--order=cpu</option></term> <listitem><para>Order by CPU load.</para></listitem> </varlistentry> <varlistentry> <term><option>-m</option></term> + <term><option>--order=memory</option></term> <listitem><para>Order by memory usage.</para></listitem> </varlistentry> <varlistentry> <term><option>-i</option></term> + <term><option>--order=io</option></term> <listitem><para>Order by disk I/O load.</para></listitem> </varlistentry> @@ -140,7 +144,7 @@ <listitem><para>Run in "batch" mode: do not accept input and run until the iteration limit set with - <option>--iterations</option> is exhausted or until killed. + <option>--iterations=</option> is exhausted or until killed. This mode could be useful for sending output from <command>systemd-cgtop</command> to other programs or to a file.</para></listitem> @@ -156,6 +160,15 @@ </varlistentry> <varlistentry> + <term><option>--cpu=percentage</option></term> + <term><option>--cpu=time</option></term> + + <listitem><para>Controls whether the CPU usage is shown as + percentage or time. By default the CPU usage is shown as + percentage.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>-n</option></term> <term><option>--iterations=</option></term> diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 27662456ea..96dc4f6620 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -61,15 +61,22 @@ resolver and an LLMNR resolver and responder. It also generates <filename>/run/systemd/resolve/resolv.conf</filename> for compatibility which may be symlinked from - <filename>/etc/resolv.conf</filename>.</para> + <filename>/etc/resolv.conf</filename>. The glibc NSS module + <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry> + is necessary to allow libc's NSS resolver functions to resolve + host names via <command>systemd-resolved</command>.</para> <para>The DNS servers contacted are determined from the global - settings in - <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - the per-link static settings in <filename>.network</filename> - files, and the per-link dynamic settings received over DHCP. See + settings in <filename>/etc/systemd/resolved.conf</filename>, the + per-link static settings in <filename>/etc/systemd/network/*.network</filename> files, + and the per-link dynamic settings received over DHCP. See + <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> + and <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for more details.</para> + for details. To improve compatibility + <filename>/etc/resolv.conf</filename> is read in order to discover + configured system DNS servers, however only if it is not a symlink + to <filename>/run/systemd/resolve/resolv.conf</filename> (see above).</para> <para><command>systemd-resolved</command> synthesizes DNS RRs for the following cases:</para> @@ -137,6 +144,7 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> </para> diff --git a/man/systemd.network.xml b/man/systemd.network.xml index e8a164d22d..ded2c0ceff 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -223,7 +223,7 @@ <varlistentry> <term><varname>DHCP=</varname></term> <listitem> - <para>Enables DHCPv4 and/or DHCPv6 support. Accepts + <para>Enables DHCPv4 and/or DHCPv6 client support. Accepts <literal>yes</literal>, <literal>no</literal>, <literal>ipv4</literal>, or <literal>ipv6</literal>.</para> @@ -235,9 +235,10 @@ <varlistentry> <term><varname>DHCPServer=</varname></term> <listitem> - <para>A boolean. Enables a basic DHCPv4 server on the - device. Mostly useful for handing out leases to container - instances.</para> + <para>A boolean. Enables DHCPv4 server support. Defaults + to <literal>no</literal>. Further settings for the DHCP + server may be set in the <literal>[DHCPServer]</literal> + section described below.</para> </listitem> </varlistentry> <varlistentry> @@ -541,7 +542,9 @@ <refsect1> <title>[DHCP] Section Options</title> - <para>The <literal>[DHCP]</literal> section accepts the following keys:</para> + <para>The <literal>[DHCP]</literal> section configures the + DHCPv4 and DHCP6 client, if it is enabled with the + <varname>DHCP=</varname> setting described above:</para> <variablelist class='network-directives'> <varlistentry> @@ -552,7 +555,8 @@ any statically configured ones.</para> <para>This corresponds to the <option>nameserver</option> - option in <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + option in <citerefentry + project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> </listitem> </varlistentry> <varlistentry> @@ -582,7 +586,7 @@ <term><varname>UseHostname=</varname></term> <listitem> <para>When true (the default), the hostname received from - the DHCP server will be used as the transient hostname. + the DHCP server will be set as the transient hostname of the system </para> </listitem> </varlistentry> @@ -615,6 +619,15 @@ table with metric of 1024.</para> </listitem> </varlistentry> + + <varlistentry> + <term><varname>UseTimezone=</varname></term> + + <listitem><para>When true, the timezone received from the + DHCP server will be set as as timezone of the local + system. Defaults to <literal>no</literal>.</para></listitem> + </varlistentry> + <varlistentry> <term><varname>CriticalConnection=</varname></term> <listitem> @@ -658,11 +671,97 @@ DHCP server.</para> </listitem> </varlistentry> - </variablelist> + </variablelist> </refsect1> <refsect1> + <title>[DHCPServer] Section Options</title> + <para>The <literal>[DHCPServer]</literal> section contains + settings for the DHCP server, if enabled via the + <varname>DHCPServer=</varname> option described above:</para> + + <variablelist class='network-directives'> + + <varlistentry> + <term><varname>DefaultLeaseTimeSec=</varname></term> + <term><varname>MaxLeaseTimeSec=</varname></term> + + <listitem><para>Control the default and maximum DHCP lease + time to pass to clients. These settings take time values in seconds or + another common time unit, depending on the suffix. The default + lease time is used for clients that did not ask for a specific + lease time. If a client asks for a lease time longer than the + maximum lease time it is automatically shortened to the + specified time. The default lease time defaults to 1h, the + maximum lease time to 12h. Shorter lease times are beneficial + if the configuration data in DHCP leases changes frequently + and clients shall learn the new settings with shorter + latencies. Longer lease times reduce the generated DHCP + network traffic.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>EmitDNS=</varname></term> + <term><varname>DNS=</varname></term> + + <listitem><para>Configures whether the DHCP leases handed out + to clients shall contain DNS server information. The + <varname>EmitDNS=</varname> setting takes a boolean argument + and defaults to <literal>yes</literal>. The DNS servers to + pass to clients may be configured with the + <varname>DNS=</varname> option, which takes a list of IPv4 + addresses. If the <varname>EmitDNS=</varname> option is + enabled but no servers configured the servers are + automatically propagated from an "uplink" interface that has + appropriate servers set. The "uplink" interface is determined + by the default route of the system with the highest + priority. Note that this information is acquired at the time + the lease is handed out, and does not take uplink interfaces + into account that acquire DNS or NTP server information at a + later point. DNS server propagation does not take + <filename>/etc/resolv.conf</filename> into account. Also, note + that the leases are not refreshed if uplink network + configuration changes. To ensure clients regularly acquire the + most current uplink DNS server information it is thus + advisable to shorten the DHCP lease time via + <varname>MaxLeaseTimeSec=</varname> described + above.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>EmitNTP=</varname></term> + <term><varname>NTP=</varname></term> + + <listitem><para>Similar to the <varname>EmitDNS=</varname> and + <varname>DNS=</varname> settings described above these + settings configure whether and what NTP server information + shall be emitted as part of the DHCP lease. The same syntax, + propagation semantics and defaults apply as for + <varname>EmitDNS=</varname> and + <varname>DNS=</varname>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>EmitTimezone=</varname></term> + <term><varname>Timezone=</varname></term> + + <listitem><para>Configures whether the DHCP leases handed out + to clients shall contain timezone information. The + <varname>EmitTimezone=</varname> setting takes a boolean + argument and defaults to <literal>yes</literal>. The + <varname>Timezone=</varname> setting takes a timezone string + (such as <literal>Europe/Berlin</literal> or + <literal>UTC</literal>) to pass to clients. If no explicit + timezone is set the system timezone of the local host is + propagated, as determined by the + <filename>/etc/localtime</filename> symlink.</para></listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <refsect1> <title>[Bridge] Section Options</title> <para>The <literal>[Bridge]</literal> section accepts the following keys.</para> diff --git a/network/80-container-host0.network b/network/80-container-host0.network index a778ecfef1..b65cc6acbe 100644 --- a/network/80-container-host0.network +++ b/network/80-container-host0.network @@ -12,3 +12,6 @@ Name=host0 [Network] DHCP=yes LinkLocalAddressing=yes + +[DHCP] +UseTimezone=yes diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index 0bcd49f923..21c79cae8e 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -112,7 +112,7 @@ _systemctl () { ;; --state) comps='loaded not-found stub - active inactive + active inactive failed dead elapsed exited listening mounted plugged running waiting' ;; --job-mode) diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index 712655caf4..63c831b8f1 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -34,10 +34,16 @@ _systemd_run() { local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} local OPTS='-h --help --version --user --system --scope --unit --description --slice -r --remain-after-exit --send-sighup -H --host -M --machine --service-type + --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive + --on-calendar --timer-property -t --pty -q --quiet --no-block --uid --gid --nice --setenv -p --property' local mode=--system local i + local opts_with_values=( + --unit --description --slice --service-type -H --host -M --machine -p --property --on-active + --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar --timer-property + ) for (( i=1; i <= COMP_CWORD; i++ )); do if [[ ${COMP_WORDS[i]} != -* ]]; then local root_command=${COMP_WORDS[i]} @@ -47,11 +53,11 @@ _systemd_run() { [[ ${COMP_WORDS[i]} == "--user" ]] && mode=--user - [[ $i -lt $COMP_CWORD && ${COMP_WORDS[i]} == @(--unit|--description|--slice|--service-type|-H|--host|-M|--machine|-p|--property) ]] && ((i++)) + [[ $i -lt $COMP_CWORD && " ${opts_with_values[@]} " =~ " ${COMP_WORDS[i]} " ]] && ((i++)) done case "$prev" in - --unit|--description) + --unit|--description|--on-active|--on-boot|--on-startup|--on-unit-active|--on-unit-inactive|--on-calendar) # argument required but no completions available return ;; @@ -92,6 +98,11 @@ _systemd_run() { COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 ;; + --timer-property) + local comps='AccuracySec= WakeSystem=' + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + ;; esac COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) diff --git a/src/basic/copy.c b/src/basic/copy.c index 33427c6a73..cc5faa80a1 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -30,7 +30,7 @@ #define COPY_BUFFER_SIZE (16*1024) int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { - bool try_sendfile = true; + bool try_sendfile = true, try_splice = true; int r; assert(fdf >= 0); @@ -69,7 +69,23 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { } else if (n == 0) /* EOF */ break; else if (n > 0) - /* Succcess! */ + /* Success! */ + goto next; + } + + /* The try splice, unless we already tried */ + if (try_splice) { + n = splice(fdf, NULL, fdt, NULL, m, 0); + if (n < 0) { + if (errno != EINVAL && errno != ENOSYS) + return -errno; + + try_splice = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Success! */ goto next; } diff --git a/src/basic/refcnt.h b/src/basic/refcnt.h index 0502c20a2e..8a39d69fe4 100644 --- a/src/basic/refcnt.h +++ b/src/basic/refcnt.h @@ -21,7 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -/* A type-safe atomic refcounter */ +/* A type-safe atomic refcounter. + * + * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ typedef struct { volatile unsigned _value; diff --git a/src/basic/ring.h b/src/basic/ring.h index a7c44d1b56..dbd6296384 100644 --- a/src/basic/ring.h +++ b/src/basic/ring.h @@ -50,7 +50,6 @@ int ring_push(Ring *r, const void *u8, size_t size); void ring_pull(Ring *r, size_t size); /* return size of occupied buffer in bytes */ -static inline size_t ring_get_size(Ring *r) -{ +static inline size_t ring_get_size(Ring *r) { return r->used; } diff --git a/src/basic/time-util.c b/src/basic/time-util.c index e278196c90..afc6a6eb24 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -26,6 +26,7 @@ #include "util.h" #include "time-util.h" +#include "path-util.h" #include "strv.h" usec_t now(clockid_t clock_id) { @@ -36,6 +37,14 @@ usec_t now(clockid_t clock_id) { return timespec_load(&ts); } +nsec_t now_nsec(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load_nsec(&ts); +} + dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { assert(ts); @@ -129,6 +138,18 @@ usec_t timespec_load(const struct timespec *ts) { (usec_t) ts->tv_nsec / NSEC_PER_USEC; } +nsec_t timespec_load_nsec(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return NSEC_INFINITY; + + return + (nsec_t) ts->tv_sec * NSEC_PER_SEC + + (nsec_t) ts->tv_nsec; +} + struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); @@ -971,7 +992,10 @@ bool timezone_is_valid(const char *name) { const char *p, *t; struct stat st; - if (!name || *name == 0 || *name == '/') + if (isempty(name)) + return false; + + if (name[0] == '/') return false; for (p = name; *p; p++) { @@ -1021,3 +1045,30 @@ clockid_t clock_boottime_or_monotonic(void) { return clock; } + +int get_timezone(char **timezone) { + _cleanup_free_ char *t = NULL; + const char *e; + char *z; + int r; + + r = readlink_malloc("/etc/localtime", &t); + if (r < 0) + return r; /* returns EINVAL if not a symlink */ + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); + if (!e) + return -EINVAL; + + if (!timezone_is_valid(e)) + return -EINVAL; + + z = strdup(e); + if (!z) + return -ENOMEM; + + *timezone = z; + return 0; +} diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 2aba042217..de881e8fe1 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -70,6 +70,7 @@ typedef struct dual_timestamp { #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) usec_t now(clockid_t clock); +nsec_t now_nsec(clockid_t clock); dual_timestamp* dual_timestamp_get(dual_timestamp *ts); dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); @@ -87,6 +88,8 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); usec_t timeval_load(const struct timeval *tv) _pure_; struct timeval *timeval_store(struct timeval *tv, usec_t u); +nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; + char *format_timestamp(char *buf, size_t l, usec_t t); char *format_timestamp_utc(char *buf, size_t l, usec_t t); char *format_timestamp_us(char *buf, size_t l, usec_t t); @@ -110,3 +113,5 @@ bool timezone_is_valid(const char *name); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0) + +int get_timezone(char **timezone); diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index fa530da456..8742ee757f 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -586,6 +586,42 @@ int unit_name_from_dbus_path(const char *path, char **name) { return 0; } +const char* unit_dbus_interface_from_type(UnitType t) { + + static const char *const table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "org.freedesktop.systemd1.Service", + [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket", + [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName", + [UNIT_TARGET] = "org.freedesktop.systemd1.Target", + [UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot", + [UNIT_DEVICE] = "org.freedesktop.systemd1.Device", + [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount", + [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount", + [UNIT_SWAP] = "org.freedesktop.systemd1.Swap", + [UNIT_TIMER] = "org.freedesktop.systemd1.Timer", + [UNIT_PATH] = "org.freedesktop.systemd1.Path", + [UNIT_SLICE] = "org.freedesktop.systemd1.Slice", + [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope", + }; + + if (t < 0) + return NULL; + if (t >= _UNIT_TYPE_MAX) + return NULL; + + return table[t]; +} + +const char *unit_dbus_interface_from_name(const char *name) { + UnitType t; + + t = unit_name_to_type(name); + if (t < 0) + return NULL; + + return unit_dbus_interface_from_type(t); +} + static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) { const char *valid_chars; @@ -787,7 +823,7 @@ static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_TIMER] = "timer", [UNIT_PATH] = "path", [UNIT_SLICE] = "slice", - [UNIT_SCOPE] = "scope" + [UNIT_SCOPE] = "scope", }; DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index b2043d0870..28b3a555f3 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -152,6 +152,9 @@ int unit_name_to_path(const char *name, char **ret); char *unit_dbus_path_from_name(const char *name); int unit_name_from_dbus_path(const char *path, char **name); +const char* unit_dbus_interface_from_type(UnitType t); +const char *unit_dbus_interface_from_name(const char *name); + typedef enum UnitNameMangle { UNIT_NAME_NOGLOB, UNIT_NAME_GLOB, diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 4ac193e22a..38b79da886 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -70,16 +70,14 @@ typedef struct { BOOLEAN no_editor; } Config; -static VOID cursor_left(UINTN *cursor, UINTN *first) -{ +static VOID cursor_left(UINTN *cursor, UINTN *first) { if ((*cursor) > 0) (*cursor)--; else if ((*first) > 0) (*first)--; } -static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) -{ +static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) { if ((*cursor)+1 < x_max) (*cursor)++; else if ((*first) + (*cursor) < len) @@ -856,13 +854,11 @@ static VOID config_entry_free(ConfigEntry *entry) { FreePool(entry->options); } -static BOOLEAN is_digit(CHAR16 c) -{ +static BOOLEAN is_digit(CHAR16 c) { return (c >= '0') && (c <= '9'); } -static UINTN c_order(CHAR16 c) -{ +static UINTN c_order(CHAR16 c) { if (c == '\0') return 0; if (is_digit(c)) @@ -873,8 +869,7 @@ static UINTN c_order(CHAR16 c) return c + 0x10000; } -static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) -{ +static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) { CHAR16 *os1 = s1; CHAR16 *os2 = s2; diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index b8d1d2ccaf..fae9398aa5 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -54,7 +54,7 @@ static void help(void) { " -a --all Show all groups, including empty\n" " -l --full Do not ellipsize output\n" " -k Include kernel threads in output\n" - " -M --machine Show container\n" + " -M --machine= Show container\n" , program_invocation_short_name); } @@ -123,146 +123,158 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -int main(int argc, char *argv[]) { - int r = 0, retval = EXIT_FAILURE; - int output_flags; - _cleanup_free_ char *root = NULL; +static int get_cgroup_root(char **ret) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_free_ char *unit = NULL, *path = NULL; + const char *m; + int r; + + if (!arg_machine) { + r = cg_get_root_path(ret); + if (r < 0) + return log_error_errno(r, "Failed to get root control group path: %m"); + + return 0; + } + + m = strjoina("/run/systemd/machines/", arg_machine); + r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL); + if (r < 0) + return log_error_errno(r, "Failed to load machine data: %m"); + + path = unit_dbus_path_from_name(unit); + if (!path) + return log_oom(); + + r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus); + if (r < 0) + return log_error_errno(r, "Failed to create bus connection: %m"); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + path, + unit_dbus_interface_from_name(unit), + "ControlGroup", + &error, + ret); + if (r < 0) + return log_error_errno(r, "Failed to query unit control group path: %m"); + + return 0; +} + +int main(int argc, char *argv[]) { + int r, output_flags; log_parse_environment(); log_open(); r = parse_argv(argc, argv); - if (r < 0) + if (r <= 0) goto finish; - else if (r == 0) { - retval = EXIT_SUCCESS; - goto finish; - } if (!arg_no_pager) { r = pager_open(false); - if (r > 0) { - if (arg_full == -1) - arg_full = true; - } + if (r > 0 && arg_full < 0) + arg_full = true; } output_flags = arg_all * OUTPUT_SHOW_ALL | (arg_full > 0) * OUTPUT_FULL_WIDTH; - r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus); - if (r < 0) { - log_error_errno(r, "Failed to create bus connection: %m"); - goto finish; - } - if (optind < argc) { + _cleanup_free_ char *root = NULL; int i; + r = get_cgroup_root(&root); + if (r < 0) + goto finish; + for (i = optind; i < argc; i++) { int q; - fprintf(stdout, "%s:\n", argv[i]); - fflush(stdout); - - if (arg_machine) - root = strjoin("machine/", arg_machine, "/", argv[i], NULL); - else - root = strdup(argv[i]); - if (!root) - return log_oom(); - - q = show_cgroup_by_path(root, NULL, 0, - arg_kernel_threads, output_flags); - if (q < 0) - r = q; - } + if (path_startswith(argv[i], "/sys/fs/cgroup")) { - } else { - _cleanup_free_ char *p; + printf("Directory %s:\n", argv[i]); + fflush(stdout); - p = get_current_dir_name(); - if (!p) { - log_error_errno(errno, "Cannot determine current working directory: %m"); - goto finish; - } + q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags); + } else { + _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL; + const char *controller, *path; - if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) { - printf("Working Directory %s:\n", p); - r = show_cgroup_by_path(p, NULL, 0, - arg_kernel_threads, output_flags); - } else { - if (arg_machine) { - char *m; - const char *cgroup; - _cleanup_free_ char *unit = NULL; - _cleanup_free_ char *path = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - - m = strjoina("/run/systemd/machines/", arg_machine); - r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL); + r = cg_split_spec(argv[i], &c, &p); if (r < 0) { - log_error_errno(r, "Failed to get machine path: %m"); + log_error_errno(r, "Failed to split argument %s: %m", argv[i]); goto finish; } - path = unit_dbus_path_from_name(unit); - if (!path) { - log_oom(); - goto finish; - } + controller = c ?: SYSTEMD_CGROUP_CONTROLLER; + if (p) { + j = strjoin(root, "/", p, NULL); + if (!j) { + r = log_oom(); + goto finish; + } - r = sd_bus_get_property( - bus, - "org.freedesktop.systemd1", - path, - endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service", - "ControlGroup", - &error, - &reply, - "s"); + path_kill_slashes(j); + path = j; + } else + path = root; - if (r < 0) { - log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); - goto finish; - } + printf("Controller %s; control group %s:\n", controller, path); + fflush(stdout); - r = sd_bus_message_read(reply, "s", &cgroup); - if (r < 0) { - bus_log_parse_error(r); - goto finish; - } + q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags); + } - root = strdup(cgroup); - if (!root) { - log_oom(); - goto finish; - } + if (q < 0) + r = q; + } + + } else { + bool done = false; - } else - r = cg_get_root_path(&root); - if (r < 0) { - log_error_errno(r, "Failed to get %s path: %m", - arg_machine ? "machine" : "root"); + if (!arg_machine) { + _cleanup_free_ char *cwd = NULL; + + cwd = get_current_dir_name(); + if (!cwd) { + r = log_error_errno(errno, "Cannot determine current working directory: %m"); goto finish; } - r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, - arg_kernel_threads, output_flags); + if (path_startswith(cwd, "/sys/fs/cgroup")) { + printf("Working directory %s:\n", cwd); + fflush(stdout); + + r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags); + done = true; + } + } + + if (!done) { + _cleanup_free_ char *root = NULL; + + r = get_cgroup_root(&root); + if (r < 0) + goto finish; + + printf("Control group %s:\n", root); + fflush(stdout); + + r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); } } - if (r < 0) { - log_error_errno(r, "Failed to list cgroup tree %s: %m", root); - retval = EXIT_FAILURE; - } else - retval = EXIT_SUCCESS; + if (r < 0) + log_error_errno(r, "Failed to list cgroup tree: %m"); finish: pager_close(); - return retval; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index f953c9e624..26b104f111 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -19,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#define __STDC_FORMAT_MACROS #include <errno.h> #include <string.h> #include <stdlib.h> @@ -48,20 +47,20 @@ typedef struct Group { unsigned n_tasks; unsigned cpu_iteration; - uint64_t cpu_usage; - struct timespec cpu_timestamp; + nsec_t cpu_usage; + nsec_t cpu_timestamp; double cpu_fraction; uint64_t memory; unsigned io_iteration; uint64_t io_input, io_output; - struct timespec io_timestamp; + nsec_t io_timestamp; uint64_t io_input_bps, io_output_bps; } Group; static unsigned arg_depth = 3; -static unsigned arg_iterations = (unsigned)-1; +static unsigned arg_iterations = (unsigned) -1; static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; @@ -111,9 +110,6 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, off_t static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) { Group *g; int r; - FILE *f = NULL; - pid_t pid; - unsigned n; assert(controller); assert(path); @@ -142,84 +138,81 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap r = hashmap_move_one(a, b, path); if (r < 0) return r; + g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false; } } - /* Regardless which controller, let's find the maximum number - * of processes in any of it */ + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { + _cleanup_fclose_ FILE *f = NULL; + pid_t pid; - r = cg_enumerate_processes(controller, path, &f); - if (r < 0) - return r; + r = cg_enumerate_processes(controller, path, &f); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; - n = 0; - while (cg_read_pid(f, &pid) > 0) - n++; - fclose(f); + g->n_tasks = 0; + while (cg_read_pid(f, &pid) > 0) + g->n_tasks++; - if (n > 0) { - if (g->n_tasks_valid) - g->n_tasks = MAX(g->n_tasks, n); - else - g->n_tasks = n; + if (g->n_tasks > 0) + g->n_tasks_valid = true; - g->n_tasks_valid = true; - } - - if (streq(controller, "cpuacct")) { + } else if (streq(controller, "cpuacct")) { + _cleanup_free_ char *p = NULL, *v = NULL; uint64_t new_usage; - char *p, *v; - struct timespec ts; + nsec_t timestamp; r = cg_get_path(controller, path, "cpuacct.usage", &p); if (r < 0) return r; r = read_one_line_file(p, &v); - free(p); + if (r == -ENOENT) + return 0; if (r < 0) return r; r = safe_atou64(v, &new_usage); - free(v); if (r < 0) return r; - assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + timestamp = now_nsec(CLOCK_MONOTONIC); - if (g->cpu_iteration == iteration - 1) { - uint64_t x, y; + if (g->cpu_iteration == iteration - 1 && + (nsec_t) new_usage > g->cpu_usage) { - x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) - - ((uint64_t) g->cpu_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->cpu_timestamp.tv_nsec); + nsec_t x, y; - y = new_usage - g->cpu_usage; + x = timestamp - g->cpu_timestamp; + if (x < 1) + x = 1; - if (y > 0) { - g->cpu_fraction = (double) y / (double) x; - g->cpu_valid = true; - } + y = (nsec_t) new_usage - g->cpu_usage; + g->cpu_fraction = (double) y / (double) x; + g->cpu_valid = true; } - g->cpu_usage = new_usage; - g->cpu_timestamp = ts; + g->cpu_usage = (nsec_t) new_usage; + g->cpu_timestamp = timestamp; g->cpu_iteration = iteration; } else if (streq(controller, "memory")) { - char *p, *v; + _cleanup_free_ char *p = NULL, *v = NULL; r = cg_get_path(controller, path, "memory.usage_in_bytes", &p); if (r < 0) return r; r = read_one_line_file(p, &v); - free(p); + if (r == -ENOENT) + return 0; if (r < 0) return r; r = safe_atou64(v, &g->memory); - free(v); if (r < 0) return r; @@ -227,19 +220,21 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap g->memory_valid = true; } else if (streq(controller, "blkio")) { - char *p; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; uint64_t wr = 0, rd = 0; - struct timespec ts; + nsec_t timestamp; r = cg_get_path(controller, path, "blkio.io_service_bytes", &p); if (r < 0) return r; f = fopen(p, "re"); - free(p); - - if (!f) + if (!f) { + if (errno == ENOENT) + return 0; return -errno; + } for (;;) { char line[LINE_MAX], *l; @@ -269,20 +264,26 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap *q += k; } - fclose(f); - - assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); + timestamp = now_nsec(CLOCK_MONOTONIC); if (g->io_iteration == iteration - 1) { uint64_t x, yr, yw; - x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) - - ((uint64_t) g->io_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->io_timestamp.tv_nsec); + x = (uint64_t) (timestamp - g->io_timestamp); + if (x < 1) + x = 1; - yr = rd - g->io_input; - yw = wr - g->io_output; + if (rd > g->io_input) + yr = rd - g->io_input; + else + yr = 0; + + if (wr > g->io_output) + yw = wr - g->io_output; + else + yw = 0; - if (g->io_input > 0 || g->io_output > 0) { + if (yr > 0 || yw > 0) { g->io_input_bps = (yr * 1000000000ULL) / x; g->io_output_bps = (yw * 1000000000ULL) / x; g->io_valid = true; @@ -291,7 +292,7 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap g->io_input = rd; g->io_output = wr; - g->io_timestamp = ts; + g->io_timestamp = timestamp; g->io_iteration = iteration; } @@ -306,7 +307,7 @@ static int refresh_one( unsigned iteration, unsigned depth) { - DIR *d = NULL; + _cleanup_closedir_ DIR *d = NULL; int r; assert(controller); @@ -321,41 +322,29 @@ static int refresh_one( return r; r = cg_enumerate_subgroups(controller, path, &d); - if (r < 0) { - if (r == -ENOENT) - return 0; - + if (r == -ENOENT) + return 0; + if (r < 0) return r; - } for (;;) { - char *fn, *p; + _cleanup_free_ char *fn = NULL, *p = NULL; r = cg_read_subgroup(d, &fn); if (r <= 0) - goto finish; + return r; p = strjoin(path, "/", fn, NULL); - free(fn); - - if (!p) { - r = -ENOMEM; - goto finish; - } + if (!p) + return -ENOMEM; path_kill_slashes(p); r = refresh_one(controller, p, a, b, iteration, depth + 1); - free(p); - if (r < 0) - goto finish; + return r; } -finish: - if (d) - closedir(d); - return r; } @@ -364,35 +353,43 @@ static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) { assert(a); - r = refresh_one("name=systemd", "/", a, b, iteration, 0); + r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, "/", a, b, iteration, 0); if (r < 0) - if (r != -ENOENT) - return r; + return r; r = refresh_one("cpuacct", "/", a, b, iteration, 0); if (r < 0) - if (r != -ENOENT) - return r; + return r; r = refresh_one("memory", "/", a, b, iteration, 0); if (r < 0) - if (r != -ENOENT) - return r; - + return r; r = refresh_one("blkio", "/", a, b, iteration, 0); if (r < 0) - if (r != -ENOENT) - return r; + return r; + return 0; } static int group_compare(const void*a, const void *b) { const Group *x = *(Group**)a, *y = *(Group**)b; - if (path_startswith(y->path, x->path)) - return -1; - if (path_startswith(x->path, y->path)) - return 1; + if (arg_order != ORDER_TASKS) { + /* Let's make sure that the parent is always before + * the child. Except when ordering by tasks, since + * that is actually not accumulative for all + * children. */ + + if (path_startswith(y->path, x->path)) + return -1; + if (path_startswith(x->path, y->path)) + return 1; + } + + switch (arg_order) { + + case ORDER_PATH: + break; - if (arg_order == ORDER_CPU) { + case ORDER_CPU: if (arg_cpu_type == CPU_PERCENT) { if (x->cpu_valid && y->cpu_valid) { if (x->cpu_fraction > y->cpu_fraction) @@ -409,10 +406,10 @@ static int group_compare(const void*a, const void *b) { else if (x->cpu_usage < y->cpu_usage) return 1; } - } - if (arg_order == ORDER_TASKS) { + break; + case ORDER_TASKS: if (x->n_tasks_valid && y->n_tasks_valid) { if (x->n_tasks > y->n_tasks) return -1; @@ -422,9 +419,10 @@ static int group_compare(const void*a, const void *b) { return -1; else if (y->n_tasks_valid) return 1; - } - if (arg_order == ORDER_MEMORY) { + break; + + case ORDER_MEMORY: if (x->memory_valid && y->memory_valid) { if (x->memory > y->memory) return -1; @@ -434,9 +432,10 @@ static int group_compare(const void*a, const void *b) { return -1; else if (y->memory_valid) return 1; - } - if (arg_order == ORDER_IO) { + break; + + case ORDER_IO: if (x->io_valid && y->io_valid) { if (x->io_input_bps + x->io_output_bps > y->io_input_bps + y->io_output_bps) return -1; @@ -448,7 +447,7 @@ static int group_compare(const void*a, const void *b) { return 1; } - return strcmp(x->path, y->path); + return path_compare(x->path, y->path); } #define ON ANSI_HIGHLIGHT_ON @@ -481,9 +480,10 @@ static int display(Hashmap *a) { for (j = 0; j < n; j++) { unsigned cputlen, pathtlen; - format_timespan(buffer, sizeof(buffer), (nsec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0); + format_timespan(buffer, sizeof(buffer), (usec_t) (array[j]->cpu_usage / NSEC_PER_USEC), 0); cputlen = strlen(buffer); maxtcpu = MAX(maxtcpu, cputlen); + pathtlen = strlen(array[j]->path); maxtpath = MAX(maxtpath, pathtlen); } @@ -503,7 +503,7 @@ static int display(Hashmap *a) { path_columns = 10; printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n", - arg_order == ORDER_PATH ? ON : "", path_columns, "Path", + arg_order == ORDER_PATH ? ON : "", path_columns, "Control Group", arg_order == ORDER_PATH ? OFF : "", arg_order == ORDER_TASKS ? ON : "", "Tasks", arg_order == ORDER_TASKS ? OFF : "", @@ -519,7 +519,7 @@ static int display(Hashmap *a) { path_columns = maxtpath; for (j = 0; j < n; j++) { - char *p; + _cleanup_free_ char *p = NULL; if (on_tty() && j + 5 > rows) break; @@ -527,8 +527,7 @@ static int display(Hashmap *a) { g = array[j]; p = ellipsize(g->path, path_columns, 33); - printf("%-*s", path_columns, p ? p : g->path); - free(p); + printf("%-*s", path_columns, p ?: g->path); if (g->n_tasks_valid) printf(" %7u", g->n_tasks); @@ -541,7 +540,7 @@ static int display(Hashmap *a) { else fputs(" -", stdout); } else - printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (nsec_t) (g->cpu_usage / NSEC_PER_USEC), 0)); + printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (usec_t) (g->cpu_usage / NSEC_PER_USEC), 0)); printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory)); printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps)); @@ -557,14 +556,15 @@ static void help(void) { printf("%s [OPTIONS...]\n\n" "Show top control groups by their resource usage.\n\n" " -h --help Show this help\n" - " --version Print version and exit\n" - " -p Order by path\n" - " -t Order by number of tasks\n" - " -c Order by CPU load\n" - " -m Order by memory load\n" - " -i Order by IO load\n" + " --version Show package version\n" + " -p --order=path Order by path\n" + " -t --order=tasks Order by number of tasks\n" + " -c --order=cpu Order by CPU load (default)\n" + " -m --order=memory Order by memory load\n" + " -i --order=io Order by IO load\n" " -r --raw Provide raw (not human-readable) numbers\n" - " --cpu[=TYPE] Show CPU usage as time or percentage (default)\n" + " --cpu=percentage Show CPU usage as percentage (default)\n" + " --cpu=time Show CPU usage as time\n" " -d --delay=DELAY Delay between updates\n" " -n --iterations=N Run for N iterations before exiting\n" " -b --batch Run in batch mode, accepting no input\n" @@ -577,18 +577,20 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_DEPTH, - ARG_CPU_TYPE + ARG_CPU_TYPE, + ARG_ORDER, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "delay", required_argument, NULL, 'd' }, - { "iterations", required_argument, NULL, 'n' }, - { "batch", no_argument, NULL, 'b' }, - { "raw", no_argument, NULL, 'r' }, - { "depth", required_argument, NULL, ARG_DEPTH }, - { "cpu", optional_argument, NULL, ARG_CPU_TYPE}, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "delay", required_argument, NULL, 'd' }, + { "iterations", required_argument, NULL, 'n' }, + { "batch", no_argument, NULL, 'b' }, + { "raw", no_argument, NULL, 'r' }, + { "depth", required_argument, NULL, ARG_DEPTH }, + { "cpu", optional_argument, NULL, ARG_CPU_TYPE }, + { "order", required_argument, NULL, ARG_ORDER }, {} }; @@ -613,13 +615,17 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CPU_TYPE: if (optarg) { - if (strcmp(optarg, "time") == 0) + if (streq(optarg, "time")) arg_cpu_type = CPU_TIME; - else if (strcmp(optarg, "percentage") == 0) + else if (streq(optarg, "percentage")) arg_cpu_type = CPU_PERCENT; - else + else { + log_error("Unknown argument to --cpu=: %s", optarg); return -EINVAL; - } + } + } else + arg_cpu_type = CPU_TIME; + break; case ARG_DEPTH: @@ -677,6 +683,23 @@ static int parse_argv(int argc, char *argv[]) { arg_order = ORDER_IO; break; + case ARG_ORDER: + if (streq(optarg, "path")) + arg_order = ORDER_PATH; + else if (streq(optarg, "tasks")) + arg_order = ORDER_TASKS; + else if (streq(optarg, "cpu")) + arg_order = ORDER_CPU; + else if (streq(optarg, "memory")) + arg_order = ORDER_MEMORY; + else if (streq(optarg, "io")) + arg_order = ORDER_IO; + else { + log_error("Invalid argument to --order=: %s", optarg); + return -EINVAL; + } + break; + case '?': return -EINVAL; @@ -715,7 +738,7 @@ int main(int argc, char *argv[]) { signal(SIGWINCH, columns_lines_cache_reset); - if (arg_iterations == (unsigned)-1) + if (arg_iterations == (unsigned) -1) arg_iterations = on_tty() ? 0 : 1; while (!quit) { @@ -753,11 +776,10 @@ int main(int argc, char *argv[]) { fputs("\n", stdout); fflush(stdout); - if (arg_batch) { + if (arg_batch) usleep(last_refresh + arg_delay - t); - } else { - r = read_one_char(stdin, &key, - last_refresh + arg_delay - t, NULL); + else { + r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL); if (r == -ETIMEDOUT) continue; if (r < 0) { @@ -843,7 +865,10 @@ int main(int argc, char *argv[]) { break; default: - fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key); + if (key < ' ') + fprintf(stdout, "\nUnknown key '\\x%x'. Ignoring.", key); + else + fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key); fflush(stdout); sleep(1); break; diff --git a/src/core/automount.c b/src/core/automount.c index 4af381b4b6..b8171ddad7 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1075,7 +1075,6 @@ const UnitVTable automount_vtable = { .reset_failed = automount_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Automount", .bus_vtable = bus_automount_vtable, .shutdown = automount_shutdown, diff --git a/src/core/busname.c b/src/core/busname.c index 9530a87311..d3c1282239 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -1058,7 +1058,6 @@ const UnitVTable busname_vtable = { .supported = busname_supported, - .bus_interface = "org.freedesktop.systemd1.BusName", .bus_vtable = bus_busname_vtable, .status_message_formats = { diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 0a9effda71..42bb653cc1 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -783,7 +783,7 @@ static int send_changed_signal(sd_bus *bus, void *userdata) { r = sd_bus_emit_properties_changed_strv( bus, p, - UNIT_VTABLE(u)->bus_interface, + unit_dbus_interface_from_type(u->type), NULL); if (r < 0) return r; diff --git a/src/core/dbus.c b/src/core/dbus.c index 44bf5cab28..d091aa5419 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -356,7 +356,7 @@ static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *in if (r <= 0) return r; - if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; *found = u; @@ -378,7 +378,7 @@ static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *inter if (r <= 0) return r; - if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; if (!unit_get_cgroup_context(u)) @@ -404,7 +404,7 @@ static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *in if (r <= 0) return r; - if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; c = unit_get_cgroup_context(u); @@ -431,7 +431,7 @@ static int bus_exec_context_find(sd_bus *bus, const char *path, const char *inte if (r <= 0) return r; - if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; c = unit_get_exec_context(u); @@ -458,7 +458,7 @@ static int bus_kill_context_find(sd_bus *bus, const char *path, const char *inte if (r <= 0) return r; - if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface)) + if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; c = unit_get_kill_context(u); @@ -555,30 +555,34 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) { return log_error_errno(r, "Failed to add job enumerator: %m"); for (t = 0; t < _UNIT_TYPE_MAX; t++) { - r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m); + const char *interface; + + assert_se(interface = unit_dbus_interface_from_type(t)); + + r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m); if (r < 0) - return log_error_errno(r, "Failed to register type specific vtable for %s: %m", unit_vtable[t]->bus_interface); + return log_error_errno(r, "Failed to register type specific vtable for %s: %m", interface); if (unit_vtable[t]->cgroup_context_offset > 0) { - r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m); + r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m); if (r < 0) - return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", unit_vtable[t]->bus_interface); + return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", interface); - r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m); + r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_cgroup_vtable, bus_cgroup_context_find, m); if (r < 0) - return log_error_errno(r, "Failed to register control group vtable for %s: %m", unit_vtable[t]->bus_interface); + return log_error_errno(r, "Failed to register control group vtable for %s: %m", interface); } if (unit_vtable[t]->exec_context_offset > 0) { - r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m); + r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_exec_vtable, bus_exec_context_find, m); if (r < 0) - return log_error_errno(r, "Failed to register execute vtable for %s: %m", unit_vtable[t]->bus_interface); + return log_error_errno(r, "Failed to register execute vtable for %s: %m", interface); } if (unit_vtable[t]->kill_context_offset > 0) { - r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m); + r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", interface, bus_kill_vtable, bus_kill_context_find, m); if (r < 0) - return log_error_errno(r, "Failed to register kill vtable for %s: %m", unit_vtable[t]->bus_interface); + return log_error_errno(r, "Failed to register kill vtable for %s: %m", interface); } } diff --git a/src/core/device.c b/src/core/device.c index e7efcf0f0a..3f574b1832 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -849,7 +849,6 @@ const UnitVTable device_vtable = { .active_state = device_active_state, .sub_state_to_string = device_sub_state_to_string, - .bus_interface = "org.freedesktop.systemd1.Device", .bus_vtable = bus_device_vtable, .following = device_following, diff --git a/src/core/mount.c b/src/core/mount.c index c0d1cdfbd4..7e19e66a51 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1871,7 +1871,6 @@ const UnitVTable mount_vtable = { .reset_failed = mount_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Mount", .bus_vtable = bus_mount_vtable, .bus_set_property = bus_mount_set_property, .bus_commit_properties = bus_mount_commit_properties, diff --git a/src/core/path.c b/src/core/path.c index 20995d920c..e9111d0612 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -770,6 +770,5 @@ const UnitVTable path_vtable = { .reset_failed = path_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Path", .bus_vtable = bus_path_vtable }; diff --git a/src/core/scope.c b/src/core/scope.c index ab1769b46b..bf89936153 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -561,7 +561,6 @@ const UnitVTable scope_vtable = { .notify_cgroup_empty = scope_notify_cgroup_empty_event, - .bus_interface = "org.freedesktop.systemd1.Scope", .bus_vtable = bus_scope_vtable, .bus_set_property = bus_scope_set_property, .bus_commit_properties = bus_scope_commit_properties, diff --git a/src/core/service.c b/src/core/service.c index b790ec98be..097e7c710c 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3214,7 +3214,6 @@ const UnitVTable service_vtable = { .bus_name_owner_change = service_bus_name_owner_change, - .bus_interface = "org.freedesktop.systemd1.Service", .bus_vtable = bus_service_vtable, .bus_set_property = bus_service_set_property, .bus_commit_properties = bus_service_commit_properties, diff --git a/src/core/slice.c b/src/core/slice.c index 064eb5d933..7442d23391 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -289,7 +289,6 @@ const UnitVTable slice_vtable = { .active_state = slice_active_state, .sub_state_to_string = slice_sub_state_to_string, - .bus_interface = "org.freedesktop.systemd1.Slice", .bus_vtable = bus_slice_vtable, .bus_set_property = bus_slice_set_property, .bus_commit_properties = bus_slice_commit_properties, diff --git a/src/core/snapshot.c b/src/core/snapshot.c index 9518e21f36..336ff20f84 100644 --- a/src/core/snapshot.c +++ b/src/core/snapshot.c @@ -302,6 +302,5 @@ const UnitVTable snapshot_vtable = { .active_state = snapshot_active_state, .sub_state_to_string = snapshot_sub_state_to_string, - .bus_interface = "org.freedesktop.systemd1.Snapshot", .bus_vtable = bus_snapshot_vtable }; diff --git a/src/core/socket.c b/src/core/socket.c index a387057473..08efc3754c 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2709,7 +2709,6 @@ const UnitVTable socket_vtable = { .reset_failed = socket_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Socket", .bus_vtable = bus_socket_vtable, .bus_set_property = bus_socket_set_property, .bus_commit_properties = bus_socket_commit_properties, diff --git a/src/core/swap.c b/src/core/swap.c index 0bc3827ff0..349fd6f7b9 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1485,7 +1485,6 @@ const UnitVTable swap_vtable = { .reset_failed = swap_reset_failed, - .bus_interface = "org.freedesktop.systemd1.Swap", .bus_vtable = bus_swap_vtable, .bus_set_property = bus_swap_set_property, .bus_commit_properties = bus_swap_commit_properties, diff --git a/src/core/target.c b/src/core/target.c index b492a7c4c7..f714cb31c2 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -221,7 +221,6 @@ const UnitVTable target_vtable = { .active_state = target_active_state, .sub_state_to_string = target_sub_state_to_string, - .bus_interface = "org.freedesktop.systemd1.Target", .bus_vtable = bus_target_vtable, .status_message_formats = { diff --git a/src/core/timer.c b/src/core/timer.c index 89758c6b19..eb6567bbfa 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -772,7 +772,6 @@ const UnitVTable timer_vtable = { .reset_failed = timer_reset_failed, .time_change = timer_time_change, - .bus_interface = "org.freedesktop.systemd1.Timer", .bus_vtable = bus_timer_vtable, .bus_set_property = bus_timer_set_property, diff --git a/src/core/unit.h b/src/core/unit.h index 9df5a7e6fb..f53b7f6da1 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -404,9 +404,6 @@ struct UnitVTable { * of this type will immediately fail. */ bool (*supported)(void); - /* The interface name */ - const char *bus_interface; - /* The bus vtable */ const sd_bus_vtable *bus_vtable; diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 7c60ef123c..df6f882af5 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -45,10 +45,10 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_ uint8_t code, size_t optlen, const void *optval); typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, - const uint8_t *option, void *user_data); + const void *option, void *userdata); int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data); + dhcp_option_cb_t cb, void *userdata); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, uint16_t arp_type, size_t optlen, diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index 5a3fcddb1b..c6b97ca8f7 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -25,7 +25,6 @@ #include <stdint.h> #include <linux/if_packet.h> -#include "refcnt.h" #include "util.h" #include "list.h" @@ -48,54 +47,62 @@ struct sd_dhcp_raw_option { }; struct sd_dhcp_lease { - RefCount n_ref; + unsigned n_ref; - int32_t time_offset; + /* each 0 if unset */ uint32_t t1; uint32_t t2; uint32_t lifetime; - uint32_t mtu_aging_timeout; + + /* each 0 if unset */ be32_t address; be32_t server_address; - be32_t subnet_mask; be32_t router; be32_t next_server; + + bool have_subnet_mask; + be32_t subnet_mask; + + bool have_broadcast; be32_t broadcast; + struct in_addr *dns; size_t dns_size; + struct in_addr *ntp; size_t ntp_size; - struct in_addr *policy_filter; - size_t policy_filter_size; + struct sd_dhcp_route *static_route; - size_t static_route_size; - size_t static_route_allocated; - uint16_t boot_file_size; - uint16_t mdr; - uint16_t mtu; - uint8_t ttl; - bool ip_forward; - bool ip_forward_non_local; + size_t static_route_size, static_route_allocated; + + uint16_t mtu; /* 0 if unset */ + char *domainname; char *hostname; char *root_path; - uint8_t *client_id; + + void *client_id; size_t client_id_len; - uint8_t *vendor_specific; + + void *vendor_specific; size_t vendor_specific_len; + + char *timezone; + LIST_HEAD(struct sd_dhcp_raw_option, private_options); }; int dhcp_lease_new(sd_dhcp_lease **ret); -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data); -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, - const uint8_t *data, uint8_t len); + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata); +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len); int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len); +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len); + +int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); +int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); #define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index b6110c5f16..36be7d54ed 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -140,7 +140,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, uint8_t *message_type, dhcp_option_cb_t cb, - void *user_data) { + void *userdata) { uint8_t code, len; size_t offset = 0; @@ -199,7 +199,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo return -EINVAL; if (cb) - cb(code, len, &options[offset], user_data); + cb(code, len, &options[offset], userdata); offset += len; @@ -214,7 +214,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo } int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data) { + dhcp_option_cb_t cb, void *userdata) { uint8_t overload = 0; uint8_t message_type = 0; int r; @@ -228,20 +228,20 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, len -= sizeof(DHCPMessage); r = parse_options(message->options, len, &overload, &message_type, - cb, user_data); + cb, userdata); if (r < 0) return r; if (overload & DHCP_OVERLOAD_FILE) { r = parse_options(message->file, sizeof(message->file), - NULL, &message_type, cb, user_data); + NULL, &message_type, cb, userdata); if (r < 0) return r; } if (overload & DHCP_OVERLOAD_SNAME) { r = parse_options(message->sname, sizeof(message->sname), - NULL, &message_type, cb, user_data); + NULL, &message_type, cb, userdata); if (r < 0) return r; } diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index 4308723f91..88a81d2866 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -137,6 +137,8 @@ enum { DHCP_OPTION_REBINDING_T2_TIME = 59, DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, + DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, DHCP_OPTION_PRIVATE_BASE = 224, DHCP_OPTION_PRIVATE_LAST = 254, diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 58750c4418..268210fc50 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -26,7 +26,6 @@ #include "sd-dhcp-server.h" #include "hashmap.h" -#include "refcnt.h" #include "util.h" #include "log.h" @@ -34,7 +33,7 @@ typedef struct DHCPClientId { size_t length; - uint8_t *data; + void *data; } DHCPClientId; typedef struct DHCPLease { @@ -47,7 +46,7 @@ typedef struct DHCPLease { } DHCPLease; struct sd_dhcp_server { - RefCount n_ref; + unsigned n_ref; sd_event *event; int event_priority; @@ -55,15 +54,21 @@ struct sd_dhcp_server { int fd; int fd_raw; - int index; + int ifindex; be32_t address; be32_t netmask; be32_t pool_start; size_t pool_size; - size_t next_offer; + + char *timezone; + + struct in_addr *ntp, *dns; + unsigned n_ntp, n_dns; Hashmap *leases_by_client_id; DHCPLease **bound_leases; + + uint32_t max_lease_time, default_lease_time; }; typedef struct DHCPRequest { @@ -75,7 +80,7 @@ typedef struct DHCPRequest { size_t max_optlen; be32_t server_id; be32_t requested_ip; - int lifetime; + uint32_t lifetime; } DHCPRequest; DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref); diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 037f580eb6..4edecf7711 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -24,13 +24,11 @@ #include <stdint.h> -#include "refcnt.h" - #include "sd-dhcp6-lease.h" #include "dhcp6-internal.h" struct sd_dhcp6_lease { - RefCount n_ref; + unsigned n_ref; uint8_t *serverid; size_t serverid_len; diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index fe56c10273..187975364b 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -41,8 +41,7 @@ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } -int dhcp_network_icmp6_bind_router_solicitation(int index) -{ +int dhcp_network_icmp6_bind_router_solicitation(int index) { struct icmp6_filter filter = { }; struct ipv6_mreq mreq = { .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, @@ -92,8 +91,7 @@ int dhcp_network_icmp6_bind_router_solicitation(int index) return r; } -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) -{ +int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { struct sockaddr_in6 dst = { .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 2fa4d5fac8..f41bebced0 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -338,9 +338,7 @@ int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, return count; } -int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, - char ***str_arr) -{ +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) { size_t pos = 0, idx = 0; _cleanup_free_ char **names = NULL; int r; diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 0f354461f7..3c04898e92 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -374,9 +374,8 @@ int lldp_mib_add_objects(Prioq *by_expiry, } /* Admission Control: Can this port attached to the existing chassis ? */ - if (REFCNT_GET(c->n_ref) >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { - log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", - REFCNT_GET(c->n_ref)); + if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { + log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); c = NULL; goto drop; @@ -394,7 +393,7 @@ int lldp_mib_add_objects(Prioq *by_expiry, /* Attach new port to chassis */ LIST_PREPEND(port, c->ports, p); - REFCNT_INC(c->n_ref); + c->n_ref ++; p = NULL; c = NULL; @@ -424,7 +423,8 @@ void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { lldp_neighbour_port_free(p); /* Drop the Chassis if no port is attached */ - if (REFCNT_DEC(c->n_ref) <= 1) { + c->n_ref --; + if (c->n_ref <= 1) { hashmap_remove(c->neighbour_mib, &c->chassis_id); lldp_chassis_free(c); } @@ -486,7 +486,7 @@ void lldp_chassis_free(lldp_chassis *c) { if (!c) return; - if (REFCNT_GET(c->n_ref) > 1) + if (c->n_ref > 1) return; free(c->chassis_id.data); @@ -513,7 +513,7 @@ int lldp_chassis_new(tlv_packet *tlv, if (!c) return -ENOMEM; - c->n_ref = REFCNT_INIT; + c->n_ref = 1; c->chassis_id.type = type; c->chassis_id.length = length; diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 8e09ee8f3a..f4eadbb87e 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -24,7 +24,6 @@ #include "log.h" #include "list.h" -#include "refcnt.h" #include "lldp-tlv.h" #include "prioq.h" @@ -63,7 +62,7 @@ struct lldp_chassis_id { }; struct lldp_chassis { - RefCount n_ref; + unsigned n_ref; lldp_chassis_id chassis_id; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index d8357c687e..26bd4088d9 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -525,7 +525,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t return 0; } -int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size) { +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) { _cleanup_free_ char *hex_buf = NULL; assert(f); @@ -541,7 +541,7 @@ int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t return 0; } -int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string) { +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) { assert(data); assert(data_len); assert(string); diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index dca82646ce..d5d4ef42f2 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -77,5 +77,5 @@ struct sd_dhcp_route; void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); -int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size); -int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string); +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 46104afded..c12768cf0e 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -27,7 +27,6 @@ #include <sys/ioctl.h> #include "util.h" -#include "refcnt.h" #include "random-util.h" #include "async.h" @@ -41,7 +40,7 @@ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) struct sd_dhcp_client { - RefCount n_ref; + unsigned n_ref; DHCPState state; sd_event *event; @@ -106,7 +105,6 @@ static const uint8_t default_req_opts[] = { DHCP_OPTION_HOST_NAME, DHCP_OPTION_DOMAIN_NAME, DHCP_OPTION_DOMAIN_NAME_SERVER, - DHCP_OPTION_NTP_SERVER, }; static int client_receive_message_raw(sd_event_source *s, int fd, @@ -377,8 +375,7 @@ static int client_initialize(sd_dhcp_client *client) { client->state = DHCP_STATE_INIT; client->xid = 0; - if (client->lease) - client->lease = sd_dhcp_lease_unref(client->lease); + client->lease = sd_dhcp_lease_unref(client->lease); return 0; } @@ -1055,18 +1052,16 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, } lease->next_server = offer->siaddr; - lease->address = offer->yiaddr; - if (lease->address == INADDR_ANY || - lease->server_address == INADDR_ANY || + if (lease->address == 0 || + lease->server_address == 0 || lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server " - "address or lease lifetime, ignoring"); + log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring"); return -ENOMSG; } - if (lease->subnet_mask == INADDR_ANY) { + if (!lease->have_subnet_mask) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { log_dhcp_client(client, "received lease lacks subnet " @@ -1168,13 +1163,17 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, return r; } -static uint64_t client_compute_timeout(sd_dhcp_client *client, - uint32_t lifetime, double factor) { +static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { assert(client); assert(client->request_sent); - assert(lifetime); + assert(lifetime > 0); - return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) + + if (lifetime > 3) + lifetime -= 3; + else + lifetime = 0; + + return client->request_sent + (lifetime * USEC_PER_SEC * factor) + + (random_u32() & 0x1fffff); } @@ -1206,7 +1205,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { /* convert the various timeouts from relative (secs) to absolute (usecs) */ lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 && client->lease->t2) { + if (client->lease->t1 > 0 && client->lease->t2 > 0) { /* both T1 and T2 are given */ if (client->lease->t1 < client->lease->t2 && client->lease->t2 < client->lease->lifetime) { @@ -1220,7 +1219,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); client->lease->t1 = client->lease->lifetime / 2; } - } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) { + } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { /* only T2 is given, and it is valid */ t2_timeout = client_compute_timeout(client, client->lease->t2, 1); t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); @@ -1230,7 +1229,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); client->lease->t2 = (client->lease->lifetime * 7) / 8; } - } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) { + } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { /* only T1 is given, and it is valid */ t1_timeout = client_compute_timeout(client, client->lease->t1, 1); t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); @@ -1676,30 +1675,41 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { } sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; return client; } sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { - if (client && REFCNT_DEC(client->n_ref) == 0) { - log_dhcp_client(client, "FREE"); - client_initialize(client); + if (!client) + return NULL; - client->receive_message = - sd_event_source_unref(client->receive_message); + assert(client->n_ref >= 1); + client->n_ref--; - sd_dhcp_client_detach_event(client); + if (client->n_ref > 0) + return NULL; - sd_dhcp_lease_unref(client->lease); + log_dhcp_client(client, "FREE"); - free(client->req_opts); - free(client->hostname); - free(client->vendor_class_identifier); - free(client); - } + client_initialize(client); + + client->receive_message = sd_event_source_unref(client->receive_message); + + sd_dhcp_client_detach_event(client); + + sd_dhcp_lease_unref(client->lease); + + free(client->req_opts); + free(client->hostname); + free(client->vendor_class_identifier); + free(client); return NULL; } @@ -1713,7 +1723,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { if (!client) return -ENOMEM; - client->n_ref = REFCNT_INIT; + client->n_ref = 1; client->state = DHCP_STATE_INIT; client->index = -1; client->fd = -1; diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index f5b9e22589..6551e7c94c 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -28,18 +28,31 @@ #include "unaligned.h" #include "in-addr-util.h" #include "hostname-util.h" +#include "dns-domain.h" +#include "network-internal.h" #include "dhcp-protocol.h" #include "dhcp-lease-internal.h" #include "sd-dhcp-lease.h" -#include "network-internal.h" -#include "dns-domain.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); + if (lease->address == 0) + return -ENODATA; + addr->s_addr = lease->address; + return 0; +} +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (!lease->have_broadcast) + return -ENODATA; + + addr->s_addr = lease->broadcast; return 0; } @@ -47,8 +60,32 @@ int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { assert_return(lease, -EINVAL); assert_return(lifetime, -EINVAL); + if (lease->lifetime <= 0) + return -ENODATA; + *lifetime = lease->lifetime; + return 0; +} + +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) { + assert_return(lease, -EINVAL); + assert_return(t1, -EINVAL); + + if (lease->t1 <= 0) + return -ENODATA; + *t1 = lease->t1; + return 0; +} + +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) { + assert_return(lease, -EINVAL); + assert_return(t2, -EINVAL); + + if (lease->t2 <= 0) + return -ENODATA; + + *t2 = lease->t2; return 0; } @@ -56,11 +93,10 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { assert_return(lease, -EINVAL); assert_return(mtu, -EINVAL); - if (lease->mtu) - *mtu = lease->mtu; - else - return -ENOENT; + if (lease->mtu <= 0) + return -ENODATA; + *mtu = lease->mtu; return 0; } @@ -68,37 +104,32 @@ int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->dns_size) { - *addr = lease->dns; - return lease->dns_size; - } else - return -ENOENT; + if (lease->dns_size <= 0) + return -ENODATA; - return 0; + *addr = lease->dns; + return (int) lease->dns_size; } int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->ntp_size) { - *addr = lease->ntp; - return lease->ntp_size; - } else - return -ENOENT; + if (lease->ntp_size <= 0) + return -ENODATA; - return 0; + *addr = lease->ntp; + return (int) lease->ntp_size; } int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { assert_return(lease, -EINVAL); assert_return(domainname, -EINVAL); - if (lease->domainname) - *domainname = lease->domainname; - else - return -ENOENT; + if (!lease->domainname) + return -ENODATA; + *domainname = lease->domainname; return 0; } @@ -106,11 +137,10 @@ int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { assert_return(lease, -EINVAL); assert_return(hostname, -EINVAL); - if (lease->hostname) - *hostname = lease->hostname; - else - return -ENOENT; + if (!lease->hostname) + return -ENODATA; + *hostname = lease->hostname; return 0; } @@ -118,11 +148,10 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { assert_return(lease, -EINVAL); assert_return(root_path, -EINVAL); - if (lease->root_path) - *root_path = lease->root_path; - else - return -ENOENT; + if (!lease->root_path) + return -ENODATA; + *root_path = lease->root_path; return 0; } @@ -130,11 +159,10 @@ int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - if (lease->router != INADDR_ANY) - addr->s_addr = lease->router; - else - return -ENOENT; + if (lease->router == 0) + return -ENODATA; + addr->s_addr = lease->router; return 0; } @@ -142,8 +170,10 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->subnet_mask; + if (!lease->have_subnet_mask) + return -ENODATA; + addr->s_addr = lease->subnet_mask; return 0; } @@ -151,8 +181,10 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->server_address; + if (lease->server_address == 0) + return -ENODATA; + addr->s_addr = lease->server_address; return 0; } @@ -160,136 +192,134 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); assert_return(addr, -EINVAL); - addr->s_addr = lease->next_server; + if (lease->next_server == 0) + return -ENODATA; + addr->s_addr = lease->next_server; return 0; } int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) { - assert_return(lease, -EINVAL); assert_return(routes, -EINVAL); - if (lease->static_route_size) { - *routes = lease->static_route; - return lease->static_route_size; - } else - return -ENOENT; + if (lease->static_route_size <= 0) + return -ENODATA; - return 0; + *routes = lease->static_route; + return (int) lease->static_route_size; } -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, - size_t *data_len) { +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) { assert_return(lease, -EINVAL); assert_return(data, -EINVAL); assert_return(data_len, -EINVAL); - if (!lease->vendor_specific) - return -ENOENT; + if (lease->vendor_specific_len <= 0) + return -ENODATA; *data = lease->vendor_specific; *data_len = lease->vendor_specific_len; - return 0; } sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; return lease; } sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) == 0) { - while (lease->private_options) { - struct sd_dhcp_raw_option *option = lease->private_options; - LIST_REMOVE(options, lease->private_options, option); + if (!lease) + return NULL; - free(option->data); - free(option); - } - free(lease->hostname); - free(lease->domainname); - free(lease->dns); - free(lease->ntp); - free(lease->static_route); - free(lease->client_id); - free(lease->vendor_specific); - free(lease); - } + assert(lease->n_ref >= 1); + lease->n_ref--; - return NULL; -} + if (lease->n_ref > 0) + return NULL; -static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - assert(option); - assert(ret); + while (lease->private_options) { + struct sd_dhcp_raw_option *option = lease->private_options; - if (len == 4) { - *ret = unaligned_read_be32((be32_t*) option); + LIST_REMOVE(options, lease->private_options, option); - if (*ret < min) - *ret = min; + free(option->data); + free(option); } -} -static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) { - lease_parse_u32(option, len, (uint32_t *)ret, 0); + free(lease->hostname); + free(lease->domainname); + free(lease->dns); + free(lease->ntp); + free(lease->static_route); + free(lease->client_id); + free(lease->vendor_specific); + free(lease); + + return NULL; } -static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { +static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { assert(option); assert(ret); - if (len == 2) { - *ret = unaligned_read_be16((be16_t*) option); + if (len != 4) + return -EINVAL; - if (*ret < min) - *ret = min; - } + *ret = unaligned_read_be32((be32_t*) option); + if (*ret < min) + *ret = min; + + return 0; } -static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { +static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { assert(option); assert(ret); - if (len == 4) - memcpy(ret, option, 4); -} + if (len != 2) + return -EINVAL; -static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) { - assert(option); - assert(ret); + *ret = unaligned_read_be16((be16_t*) option); + if (*ret < min) + *ret = min; - if (len == 1) - *ret = !!(*option); + return 0; } -static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) { +static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { assert(option); assert(ret); - if (len == 1) { - *ret = *option; + if (len != 4) + return -EINVAL; - if (*ret < min) - *ret = min; - } + memcpy(ret, option, 4); + return 0; } static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { assert(option); assert(ret); - if (len >= 1) { + if (len <= 0) + *ret = mfree(*ret); + else { char *string; + if (memchr(option, 0, len)) + return -EINVAL; + string = strndup((const char *)option, len); if (!string) - return -errno; + return -ENOMEM; free(*ret); *ret = string; @@ -298,48 +328,47 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { return 0; } -static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) { +static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); - assert(ret_size); + assert(n_ret); - if (len && !(len % (4 * mult))) { - size_t size; + if (len <= 0) { + *ret = mfree(*ret); + *n_ret = 0; + } else { + size_t n_addresses; struct in_addr *addresses; - size = len / 4; + if (len % 4 != 0) + return -EINVAL; + + n_addresses = len / 4; - addresses = newdup(struct in_addr, option, size); + addresses = newdup(struct in_addr, option, n_addresses); if (!addresses) return -ENOMEM; free(*ret); *ret = addresses; - *ret_size = size; + *n_ret = n_addresses; } return 0; } -static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1); -} - -static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2); -} - -static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { +static int lease_parse_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { struct in_addr addr; - assert(option); + assert(option || len <= 0); assert(routes); assert(routes_size); assert(routes_allocated); - if (!len) + if (len <= 0) return 0; if (len % 8 != 0) @@ -354,15 +383,15 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_ r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); if (r < 0) { - log_error("Failed to determine destination prefix length from class based IP, ignoring"); + log_debug("Failed to determine destination prefix length from class based IP, ignoring"); continue; } - lease_parse_be32(option, 4, &addr.s_addr); + assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0); route->dst_addr = inet_makeaddr(inet_netof(addr), 0); option += 4; - lease_parse_be32(option, 4, &route->gw_addr.s_addr); + assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); option += 4; len -= 8; @@ -373,14 +402,18 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_ } /* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { +static int lease_parse_classless_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { - assert(option); + assert(option || len <= 0); assert(routes); assert(routes_size); assert(routes_allocated); + if (len <= 0) + return 0; + /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */ while (len > 0) { @@ -388,7 +421,7 @@ static int lease_parse_classless_routes(const uint8_t *option, size_t len, struc struct sd_dhcp_route *route; if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1)) - return -ENOMEM; + return -ENOMEM; route = *routes + *routes_size; @@ -419,223 +452,222 @@ static int lease_parse_classless_routes(const uint8_t *option, size_t len, struc return 0; } -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) { - sd_dhcp_lease *lease = user_data; +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) { + sd_dhcp_lease *lease = userdata; int r; assert(lease); switch(code) { - case DHCP_OPTION_TIME_OFFSET: - lease_parse_s32(option, len, &lease->time_offset); - - break; - - case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT: - lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0); - - break; - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - lease_parse_u32(option, len, &lease->lifetime, 1); + r = lease_parse_u32(option, len, &lease->lifetime, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); break; case DHCP_OPTION_SERVER_IDENTIFIER: - lease_parse_be32(option, len, &lease->server_address); + r = lease_parse_be32(option, len, &lease->server_address); + if (r < 0) + log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); break; case DHCP_OPTION_SUBNET_MASK: - lease_parse_be32(option, len, &lease->subnet_mask); - + r = lease_parse_be32(option, len, &lease->subnet_mask); + if (r < 0) + log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); + else + lease->have_subnet_mask = true; break; case DHCP_OPTION_BROADCAST: - lease_parse_be32(option, len, &lease->broadcast); - + r = lease_parse_be32(option, len, &lease->broadcast); + if (r < 0) + log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); + else + lease->have_broadcast = true; break; case DHCP_OPTION_ROUTER: - if(len >= 4) - lease_parse_be32(option, 4, &lease->router); - + if (len >= 4) { + r = lease_parse_be32(option, 4, &lease->router); + if (r < 0) + log_debug_errno(r, "Failed to parse router address, ignoring: %m"); + } break; case DHCP_OPTION_DOMAIN_NAME_SERVER: r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); break; case DHCP_OPTION_NTP_SERVER: r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size); if (r < 0) - return r; - - break; - - case DHCP_OPTION_POLICY_FILTER: - r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size); - if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); break; case DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); + r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); break; case DHCP_OPTION_INTERFACE_MTU: - lease_parse_u16(option, len, &lease->mtu, 68); - - break; - - case DHCP_OPTION_INTERFACE_MDR: - lease_parse_u16(option, len, &lease->mdr, 576); - - break; - - case DHCP_OPTION_INTERFACE_TTL: - lease_parse_u8(option, len, &lease->ttl, 1); - - break; - - case DHCP_OPTION_BOOT_FILE_SIZE: - lease_parse_u16(option, len, &lease->boot_file_size, 0); - + r = lease_parse_u16(option, len, &lease->mtu, 68); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); break; - case DHCP_OPTION_DOMAIN_NAME: - { - _cleanup_free_ char *domainname = NULL; - char *e; + case DHCP_OPTION_DOMAIN_NAME: { + _cleanup_free_ char *domainname = NULL, *normalized = NULL; r = lease_parse_string(option, len, &domainname); - if (r < 0) - return r; - - /* Chop off trailing dot of domain name that some DHCP - * servers send us back. Internally we want to store - * host names without trailing dots and - * host_name_is_valid() doesn't accept them. */ - e = endswith(domainname, "."); - if (e) - *e = 0; + if (r < 0) { + log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); + return 0; + } - if (is_localhost(domainname)) - break; + r = dns_name_normalize(domainname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname); + return 0; + } - r = dns_name_is_valid(domainname); - if (r <= 0) { - if (r < 0) - log_error_errno(r, "Failed to validate domain name: %s: %m", domainname); - if (r == 0) - log_warning("Domain name is not valid, ignoring: %s", domainname); + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring."); break; } free(lease->domainname); - lease->domainname = domainname; - domainname = NULL; + lease->domainname = normalized; + normalized = NULL; break; } - case DHCP_OPTION_HOST_NAME: - { - _cleanup_free_ char *hostname = NULL; - char *e; + + case DHCP_OPTION_HOST_NAME: { + _cleanup_free_ char *hostname = NULL, *normalized = NULL; r = lease_parse_string(option, len, &hostname); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to parse host name, ignoring: %m"); + return 0; + } - e = endswith(hostname, "."); - if (e) - *e = 0; + r = dns_name_normalize(hostname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname); + return 0; + } - if (!hostname_is_valid(hostname, false) || is_localhost(hostname)) - break; + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring."); + return 0; + } - free_and_replace(&lease->hostname, hostname); - hostname = NULL; + free(lease->hostname); + lease->hostname = normalized; + normalized = NULL; break; } + case DHCP_OPTION_ROOT_PATH: r = lease_parse_string(option, len, &lease->root_path); if (r < 0) - return r; - + log_debug_errno(r, "Failed to parse root path, ignoring: %m"); break; case DHCP_OPTION_RENEWAL_T1_TIME: - lease_parse_u32(option, len, &lease->t1, 1); - + r = lease_parse_u32(option, len, &lease->t1, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); break; case DHCP_OPTION_REBINDING_T2_TIME: - lease_parse_u32(option, len, &lease->t2, 1); - + r = lease_parse_u32(option, len, &lease->t2, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); break; - case DHCP_OPTION_ENABLE_IP_FORWARDING: - lease_parse_bool(option, len, &lease->ip_forward); - + case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: + r = lease_parse_classless_routes( + option, len, + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated); + if (r < 0) + log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); break; - case DHCP_OPTION_ENABLE_IP_FORWARDING_NL: - lease_parse_bool(option, len, &lease->ip_forward_non_local); + case DHCP_OPTION_NEW_TZDB_TIMEZONE: { + _cleanup_free_ char *tz = NULL; - break; + r = lease_parse_string(option, len, &tz); + if (r < 0) { + log_debug_errno(r, "Failed to parse timezone option, ignoring: %m"); + return 0; + } - case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); - if (r < 0) - return r; + if (!timezone_is_valid(tz)) { + log_debug_errno(r, "Timezone is not valid, ignoring: %m"); + return 0; + } + + free(lease->timezone); + lease->timezone = tz; + tz = NULL; break; + } case DHCP_OPTION_VENDOR_SPECIFIC: - if (len >= 1) { - free(lease->vendor_specific); - lease->vendor_specific = memdup(option, len); - if (!lease->vendor_specific) + + if (len <= 0) + lease->vendor_specific = mfree(lease->vendor_specific); + else { + void *p; + + p = memdup(option, len); + if (!p) return -ENOMEM; - lease->vendor_specific_len = len; - } - break; + free(lease->vendor_specific); + lease->vendor_specific = p; + } - default: - if (code < DHCP_OPTION_PRIVATE_BASE || code > DHCP_OPTION_PRIVATE_LAST) - break; + lease->vendor_specific_len = len; + break; + case DHCP_OPTION_PRIVATE_BASE ... DHCP_OPTION_PRIVATE_LAST: r = dhcp_lease_insert_private_option(lease, code, option, len); if (r < 0) return r; + + break; + + default: + log_debug("Ignoring option DHCP option %i while parsing.", code); + break; } return 0; } -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, - const uint8_t *data, uint8_t len) { +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) { struct sd_dhcp_raw_option *cur, *option; + assert(lease); + LIST_FOREACH(options, cur, lease->private_options) { if (tag < cur->tag) break; - else if (tag == cur->tag) { - log_error("Ignoring duplicate option, tagged %d.", tag); + if (tag == cur->tag) { + log_debug("Ignoring duplicate option, tagged %i.", tag); return 0; } } @@ -653,7 +685,6 @@ int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, } LIST_INSERT_BEFORE(options, lease->private_options, cur, option); - return 0; } @@ -665,24 +696,24 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { return -ENOMEM; lease->router = INADDR_ANY; - lease->n_ref = REFCNT_INIT; - LIST_HEAD_INIT(lease->private_options); + lease->n_ref = 1; *ret = lease; return 0; } -int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { +int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; struct sd_dhcp_raw_option *option; struct in_addr address; const struct in_addr *addresses; - const uint8_t *client_id, *data; + const void *client_id, *data; size_t client_id_len, data_len; const char *string; uint16_t mtu; struct sd_dhcp_route *routes; + uint32_t t1, t2, lifetime; int r; assert(lease); @@ -694,19 +725,16 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fchmod(fileno(f), 0644); - r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) - goto fail; - fprintf(f, - "# This is private data. Do not parse.\n" - "ADDRESS=%s\n", inet_ntoa(address)); + "# This is private data. Do not parse.\n"); - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r < 0) - goto fail; + r = sd_dhcp_lease_get_address(lease, &address); + if (r >= 0) + fprintf(f, "ADDRESS=%s\n", inet_ntoa(address)); - fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_netmask(lease, &address); + if (r >= 0) + fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); r = sd_dhcp_lease_get_router(lease, &address); if (r >= 0) @@ -714,28 +742,45 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_server_identifier(lease, &address); if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", - inet_ntoa(address)); + fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address)); r = sd_dhcp_lease_get_next_server(lease, &address); if (r >= 0) fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_broadcast(lease, &address); + if (r >= 0) + fprintf(f, "BROADCAST=%s\n", inet_ntoa(address)); + r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) fprintf(f, "MTU=%" PRIu16 "\n", mtu); - fputs("DNS=", f); - r = sd_dhcp_lease_get_dns(lease, &addresses); + r = sd_dhcp_lease_get_t1(lease, &t1); + if (r >= 0) + fprintf(f, "T1=%" PRIu32 "\n", t1); + + r = sd_dhcp_lease_get_t2(lease, &t2); + if (r >= 0) + fprintf(f, "T2=%" PRIu32 "\n", t2); + + r = sd_dhcp_lease_get_lifetime(lease, &lifetime); if (r >= 0) + fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime); + + r = sd_dhcp_lease_get_dns(lease, &addresses); + if (r > 0) { + fputs("DNS=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs("\n", f); + } - fputs("NTP=", f); r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r >= 0) + if (r > 0) { + fputs("NTP=", f); serialize_in_addrs(f, addresses, r); - fputs("\n", f); + fputs("\n", f); + } r = sd_dhcp_lease_get_domainname(lease, &string); if (r >= 0) @@ -750,9 +795,13 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fprintf(f, "ROOT_PATH=%s\n", string); r = sd_dhcp_lease_get_routes(lease, &routes); - if (r >= 0) + if (r > 0) serialize_dhcp_routes(f, "ROUTES", routes, r); + r = sd_dhcp_lease_get_timezone(lease, &string); + if (r >= 0) + fprintf(f, "TIMEZONE=%s\n", string); + r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); if (r >= 0) { _cleanup_free_ char *client_id_hex; @@ -779,6 +828,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { LIST_FOREACH(options, option, lease->private_options) { char key[strlen("OPTION_000")+1]; + snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length); if (r < 0) @@ -803,16 +853,27 @@ fail: return log_error_errno(r, "Failed to save lease data %s: %m", lease_file); } -int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { +int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { + _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; - _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL, - *server_address = NULL, *next_server = NULL, - *dns = NULL, *ntp = NULL, *mtu = NULL, - *routes = NULL, *client_id_hex = NULL, - *vendor_specific_hex = NULL, - *options[DHCP_OPTION_PRIVATE_LAST - - DHCP_OPTION_PRIVATE_BASE + 1] = { NULL }; - struct in_addr addr; + _cleanup_free_ char + *address = NULL, + *router = NULL, + *netmask = NULL, + *server_address = NULL, + *next_server = NULL, + *broadcast = NULL, + *dns = NULL, + *ntp = NULL, + *mtu = NULL, + *routes = NULL, + *client_id_hex = NULL, + *vendor_specific_hex = NULL, + *lifetime = NULL, + *t1 = NULL, + *t2 = NULL, + *options[DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE + 1] = {}; + int r, i; assert(lease_file); @@ -828,6 +889,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "NETMASK", &netmask, "SERVER_IDENTIFIER", &server_address, "NEXT_SERVER", &next_server, + "BROADCAST", &broadcast, "DNS", &dns, "NTP", &ntp, "MTU", &mtu, @@ -836,7 +898,11 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "ROOT_PATH", &lease->root_path, "ROUTES", &routes, "CLIENTID", &client_id_hex, + "TIMEZONE", &lease->timezone, "VENDOR_SPECIFIC", &vendor_specific_hex, + "LIFETIME", &lifetime, + "T1", &t1, + "T2", &t2, "OPTION_224", &options[0], "OPTION_225", &options[1], "OPTION_226", &options[2], @@ -869,100 +935,123 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "OPTION_253", &options[29], "OPTION_254", &options[30], NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - - return log_error_errno(r, "Failed to read %s: %m", lease_file); - } - - r = inet_pton(AF_INET, address, &addr); if (r < 0) return r; - lease->address = addr.s_addr; + if (address) { + r = inet_pton(AF_INET, address, &lease->address); + if (r <= 0) + log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address); + } if (router) { - r = inet_pton(AF_INET, router, &addr); - if (r < 0) - return r; - - lease->router = addr.s_addr; + r = inet_pton(AF_INET, router, &lease->router); + if (r <= 0) + log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router); } - r = inet_pton(AF_INET, netmask, &addr); - if (r < 0) - return r; - - lease->subnet_mask = addr.s_addr; + if (netmask) { + r = inet_pton(AF_INET, netmask, &lease->subnet_mask); + if (r <= 0) + log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask); + else + lease->have_subnet_mask = true; + } if (server_address) { - r = inet_pton(AF_INET, server_address, &addr); - if (r < 0) - return r; - - lease->server_address = addr.s_addr; + r = inet_pton(AF_INET, server_address, &lease->server_address); + if (r <= 0) + log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address); } if (next_server) { - r = inet_pton(AF_INET, next_server, &addr); - if (r < 0) - return r; + r = inet_pton(AF_INET, next_server, &lease->next_server); + if (r <= 0) + log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server); + } - lease->next_server = addr.s_addr; + if (broadcast) { + r = inet_pton(AF_INET, broadcast, &lease->broadcast); + if (r <= 0) + log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast); + else + lease->have_broadcast = true; } if (dns) { r = deserialize_in_addrs(&lease->dns, dns); if (r < 0) - return r; - - lease->dns_size = r; + log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); + else + lease->dns_size = r; } if (ntp) { r = deserialize_in_addrs(&lease->ntp, ntp); if (r < 0) - return r; - - lease->ntp_size = r; + log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); + else + lease->ntp_size = r; } if (mtu) { - uint16_t u; - if (sscanf(mtu, "%" SCNu16, &u) > 0) - lease->mtu = u; + r = safe_atou16(mtu, &lease->mtu); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu); } if (routes) { - r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size, - &lease->static_route_allocated, routes); + r = deserialize_dhcp_routes( + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated, + routes); + if (r < 0) + log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes); + } + + if (lifetime) { + r = safe_atou32(lifetime, &lease->lifetime); + if (r < 0) + log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime); + } + + if (t1) { + r = safe_atou32(t1, &lease->t1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1); + } + + if (t2) { + r = safe_atou32(t2, &lease->t2); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2); } if (client_id_hex) { r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); } if (vendor_specific_hex) { r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex); if (r < 0) - return r; + log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); } for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) { - _cleanup_free_ uint8_t *data = NULL; + _cleanup_free_ void *data = NULL; size_t len; if (!options[i]) continue; r = deserialize_dhcp_option(&data, &len, options[i]); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); + continue; + } r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len); if (r < 0) @@ -976,12 +1065,14 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - struct in_addr address; - struct in_addr mask; + struct in_addr address, mask; int r; assert(lease); + if (lease->address == 0) + return -ENODATA; + address.s_addr = lease->address; /* fall back to the default subnet masks based on address class */ @@ -990,35 +1081,53 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { return r; lease->subnet_mask = mask.s_addr; + lease->have_subnet_mask = true; return 0; } -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len) { +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) { assert_return(lease, -EINVAL); assert_return(client_id, -EINVAL); assert_return(client_id_len, -EINVAL); + if (!lease->client_id) + return -ENODATA; + *client_id = lease->client_id; *client_id_len = lease->client_id_len; + return 0; } -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len) { +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) { assert_return(lease, -EINVAL); - assert_return((!client_id && !client_id_len) || - (client_id && client_id_len), -EINVAL); + assert_return(client_id || client_id_len <= 0, -EINVAL); + + if (client_id_len <= 0) + lease->client_id = mfree(lease->client_id); + else { + void *p; - free (lease->client_id); - lease->client_id = NULL; - lease->client_id_len = 0; + p = memdup(client_id, client_id_len); + if (!p) + return -ENOMEM; - if (client_id) { - lease->client_id = memdup (client_id, client_id_len); + free(lease->client_id); + lease->client_id = p; lease->client_id_len = client_id_len; } return 0; } + +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone) { + assert_return(lease, -EINVAL); + assert_return(timezone, -EINVAL); + + if (!lease->timezone) + return -ENODATA; + + *timezone = lease->timezone; + return 0; +} diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index faeab0fd30..89b9a4c6be 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -28,7 +28,8 @@ #include "dhcp-server-internal.h" #include "dhcp-internal.h" -#define DHCP_DEFAULT_LEASE_TIME 3600 /* one hour */ +#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR +#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *address, @@ -73,8 +74,12 @@ bool sd_dhcp_server_is_running(sd_dhcp_server *server) { } sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) { - if (server) - assert_se(REFCNT_INC(server->n_ref) >= 2); + + if (!server) + return NULL; + + assert(server->n_ref >= 1); + server->n_ref++; return server; } @@ -127,7 +132,10 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { if (!server) return NULL; - if (REFCNT_DEC(server->n_ref) > 0) + assert(server->n_ref >= 1); + server->n_ref--; + + if (server->n_ref > 0) return NULL; log_dhcp_server(server, "UNREF"); @@ -136,6 +144,10 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { sd_event_unref(server->event); + free(server->timezone); + free(server->dns); + free(server->ntp); + while ((lease = hashmap_steal_first(server->leases_by_client_id))) dhcp_lease_free(lease); hashmap_free(server->leases_by_client_id); @@ -156,13 +168,15 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { if (!server) return -ENOMEM; - server->n_ref = REFCNT_INIT; + server->n_ref = 1; server->fd_raw = -1; server->fd = -1; server->address = htobe32(INADDR_ANY); server->netmask = htobe32(INADDR_ANY); - server->index = ifindex; + server->ifindex = ifindex; server->leases_by_client_id = hashmap_new(&client_id_hash_ops); + server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC); + server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC); *ret = server; server = NULL; @@ -223,13 +237,12 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, union sockaddr_union link = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htons(ETH_P_IP), - .ll.sll_ifindex = server->index, + .ll.sll_ifindex = server->ifindex, .ll.sll_halen = ETH_ALEN, }; - int r; assert(server); - assert(server->index > 0); + assert(server->ifindex > 0); assert(server->address); assert(packet); assert(len > sizeof(DHCPPacket)); @@ -240,11 +253,7 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, packet->dhcp.yiaddr, DHCP_PORT_CLIENT, len); - r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len); - if (r < 0) - return r; - - return 0; + return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len); } static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination, @@ -290,7 +299,7 @@ static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination, pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg); assert(pktinfo); - pktinfo->ipi_ifindex = server->index; + pktinfo->ipi_ifindex = server->ifindex; pktinfo->ipi_spec_dst.s_addr = server->address; r = sendmsg(server->fd, &msg, 0); @@ -474,6 +483,33 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; + if (server->n_dns > 0) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_DOMAIN_NAME_SERVER, + sizeof(struct in_addr) * server->n_dns, server->dns); + if (r < 0) + return r; + } + + if (server->n_ntp > 0) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_NTP_SERVER, + sizeof(struct in_addr) * server->n_ntp, server->ntp); + if (r < 0) + return r; + } + + if (server->timezone) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_NEW_TZDB_TIMEZONE, + strlen(server->timezone), server->timezone); + if (r < 0) + return r; + } + r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset); if (r < 0) return r; @@ -490,11 +526,7 @@ static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) { if (r < 0) return r; - r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset); - if (r < 0) - return r; - - return 0; + return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset); } static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, @@ -532,9 +564,8 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, return 0; } -static int parse_request(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) { - DHCPRequest *req = user_data; +static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) { + DHCPRequest *req = userdata; assert(req); @@ -590,7 +621,7 @@ static void dhcp_request_free(DHCPRequest *req) { DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free); #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep) -static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) { +static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) { assert(req); assert(message); @@ -599,23 +630,27 @@ static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) { /* set client id based on MAC address if client did not send an explicit one */ if (!req->client_id.data) { - uint8_t *data; + void *data; - data = new0(uint8_t, ETH_ALEN + 1); + data = malloc0(ETH_ALEN + 1); if (!data) return -ENOMEM; + ((uint8_t*) data)[0] = 0x01; + memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN); + req->client_id.length = ETH_ALEN + 1; req->client_id.data = data; - req->client_id.data[0] = 0x01; - memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN); } if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE) req->max_optlen = DHCP_MIN_OPTIONS_SIZE; - if (!req->lifetime) - req->lifetime = DHCP_DEFAULT_LEASE_TIME; + if (req->lifetime <= 0) + req->lifetime = MAX(1ULL, server->default_lease_time); + + if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time) + req->lifetime = server->max_lease_time; return 0; } @@ -634,6 +669,8 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) { return be32toh(requested_ip) - be32toh(server->pool_start); } +#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30) + int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length) { _cleanup_dhcp_request_free_ DHCPRequest *req = NULL; @@ -656,7 +693,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, if (type < 0) return 0; - r = ensure_sane_request(req, message); + r = ensure_sane_request(server, req, message); if (r < 0) /* this only fails on critical errors */ return r; @@ -665,8 +702,8 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, &req->client_id); switch(type) { - case DHCP_DISCOVER: - { + + case DHCP_DISCOVER: { be32_t address = INADDR_ANY; unsigned i; @@ -681,12 +718,20 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, if (existing_lease) address = existing_lease->address; else { + size_t next_offer; + + /* even with no persistence of leases, we try to offer the same client + the same IP address. we do this by using the hash of the client id + as the offset into the pool of leases when finding the next free one */ + + next_offer = client_id_hash_func(&req->client_id, HASH_KEY.bytes) % server->pool_size; + for (i = 0; i < server->pool_size; i++) { - if (!server->bound_leases[server->next_offer]) { - address = htobe32(be32toh(server->pool_start) + server->next_offer); + if (!server->bound_leases[next_offer]) { + address = htobe32(be32toh(server->pool_start) + next_offer); break; } else - server->next_offer = (server->next_offer + 1) % server->pool_size; + next_offer = (next_offer + 1) % server->pool_size; } } @@ -716,9 +761,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, return 1; - break; - case DHCP_REQUEST: - { + case DHCP_REQUEST: { be32_t address; bool init_reboot = false; int pool_offset; @@ -840,6 +883,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, break; } + case DHCP_RELEASE: { int pool_offset; @@ -883,13 +927,12 @@ static int server_receive_message(sd_event_source *s, int fd, .msg_controllen = sizeof(cmsgbuf), }; struct cmsghdr *cmsg; - int buflen = 0, len, r; + int buflen = 0, len; assert(server); - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return r; + if (ioctl(fd, FIONREAD, &buflen) < 0) + return -errno; if (buflen < 0) return -EIO; @@ -914,7 +957,7 @@ static int server_receive_message(sd_event_source *s, int fd, /* TODO figure out if this can be done as a filter on * the socket, like for IPv6 */ - if (server->index != info->ipi_ifindex) + if (server->ifindex != info->ipi_ifindex) return 0; break; @@ -993,3 +1036,91 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server) { return r; } + +int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone) { + int r; + + assert_return(server, -EINVAL); + assert_return(timezone_is_valid(timezone), -EINVAL); + + if (streq_ptr(timezone, server->timezone)) + return 0; + + r = free_and_strdup(&server->timezone, timezone); + if (r < 0) + return r; + + return 1; +} + +int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) { + assert_return(server, -EINVAL); + + if (t == server->max_lease_time) + return 0; + + server->max_lease_time = t; + return 1; +} + +int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) { + assert_return(server, -EINVAL); + + if (t == server->default_lease_time) + return 0; + + server->default_lease_time = t; + return 1; +} + +int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) { + assert_return(server, -EINVAL); + assert_return(dns || n <= 0, -EINVAL); + + if (server->n_dns == n && + memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0) + return 0; + + if (n <= 0) { + server->dns = mfree(server->dns); + server->n_dns = 0; + } else { + struct in_addr *c; + + c = newdup(struct in_addr, dns, n); + if (!c) + return -ENOMEM; + + free(server->dns); + server->dns = c; + server->n_dns = n; + } + + return 1; +} + +int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) { + assert_return(server, -EINVAL); + assert_return(ntp || n <= 0, -EINVAL); + + if (server->n_ntp == n && + memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0) + return 0; + + if (n <= 0) { + server->ntp = mfree(server->ntp); + server->n_ntp = 0; + } else { + struct in_addr *c; + + c = newdup(struct in_addr, ntp, n); + if (!c) + return -ENOMEM; + + free(server->ntp); + server->ntp = c; + server->n_ntp = n; + } + + return 1; +} diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 10c3654020..5489c77864 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -27,7 +27,6 @@ #include "udev.h" #include "udev-util.h" #include "util.h" -#include "refcnt.h" #include "random-util.h" #include "network-internal.h" @@ -40,7 +39,7 @@ #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN struct sd_dhcp6_client { - RefCount n_ref; + unsigned n_ref; enum DHCP6State state; sd_event *event; @@ -113,9 +112,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata) -{ +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -124,8 +121,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) -{ +int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { assert_return(client, -EINVAL); assert_return(interface_index >= -1, -EINVAL); @@ -134,9 +130,11 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) return 0; } -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) -{ +int sd_dhcp6_client_set_mac( + sd_dhcp6_client *client, + const uint8_t *addr, size_t addr_len, + uint16_t arp_type) { + assert_return(client, -EINVAL); assert_return(addr, -EINVAL); assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); @@ -160,16 +158,17 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, return 0; } -static int client_ensure_duid(sd_dhcp6_client *client) -{ +static int client_ensure_duid(sd_dhcp6_client *client) { if (client->duid_len != 0) return 0; + return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len) -{ +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t type, + uint8_t *duid, size_t duid_len) { assert_return(client, -EINVAL); assert_return(duid, -EINVAL); assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); @@ -203,8 +202,7 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du return 0; } -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, - bool enabled) { +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) { assert_return(client, -EINVAL); client->information_request = enabled; @@ -212,8 +210,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, - bool *enabled) { +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) { assert_return(client, -EINVAL); assert_return(enabled, -EINVAL); @@ -222,8 +219,7 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, return 0; } -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option) { +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) { size_t t; assert_return(client, -EINVAL); @@ -805,9 +801,7 @@ static int client_parse_message(sd_dhcp6_client *client, return r; } -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, - size_t len) -{ +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { int r; _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; bool rapid_commit; @@ -843,8 +837,7 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, return DHCP6_STATE_BOUND; } -static int client_receive_advertise(sd_dhcp6_client *client, - DHCP6Message *advertise, size_t len) { +static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { int r; _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; @@ -879,8 +872,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, return r; } -static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, - void *userdata) { +static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); _cleanup_free_ DHCP6Message *message; @@ -991,8 +983,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; } -static int client_start(sd_dhcp6_client *client, enum DHCP6State state) -{ +static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { int r; usec_t timeout, time_now; char time_string[FORMAT_TIMESPAN_MAX]; @@ -1121,15 +1112,13 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) return 0; } -int sd_dhcp6_client_stop(sd_dhcp6_client *client) -{ +int sd_dhcp6_client_stop(sd_dhcp6_client *client) { client_stop(client, DHCP6_EVENT_STOP); return 0; } -int sd_dhcp6_client_start(sd_dhcp6_client *client) -{ +int sd_dhcp6_client_start(sd_dhcp6_client *client) { int r = 0; enum DHCP6State state = DHCP6_STATE_SOLICITATION; @@ -1185,9 +1174,7 @@ error: return r; } -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority) -{ +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) { int r; assert_return(client, -EINVAL); @@ -1222,30 +1209,39 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { } sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; return client; } sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { - if (client && REFCNT_DEC(client->n_ref) == 0) { - client_reset(client); - sd_dhcp6_client_detach_event(client); - sd_dhcp6_lease_unref(client->lease); + if (!client) + return NULL; - free(client->req_opts); - free(client); + assert(client->n_ref >= 1); + client->n_ref--; + if (client->n_ref > 0) return NULL; - } - return client; + client_reset(client); + + sd_dhcp6_client_detach_event(client); + sd_dhcp6_lease_unref(client->lease); + + free(client->req_opts); + free(client); + + return NULL; } -int sd_dhcp6_client_new(sd_dhcp6_client **ret) -{ +int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; size_t t; @@ -1255,7 +1251,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) if (!client) return -ENOMEM; - client->n_ref = REFCNT_INIT; + client->n_ref = 1; client->ia_na.type = DHCP6_OPTION_IA_NA; diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index f0494b3c91..f34af6eaba 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -247,8 +247,7 @@ int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) { return -ENOENT; } -int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) -{ +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { int r; uint16_t subopt; size_t sublen; @@ -361,26 +360,38 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { } sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; return lease; } sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) == 0) { - free(lease->serverid); - dhcp6_lease_free_ia(&lease->ia); - free(lease->dns); + if (!lease) + return NULL; - lease->domains = strv_free(lease->domains); + assert(lease->n_ref >= 1); + lease->n_ref--; - free(lease->ntp); + if (lease->n_ref > 0) + return NULL; - lease->ntp_fqdn = strv_free(lease->ntp_fqdn); - free(lease); - } + free(lease->serverid); + dhcp6_lease_free_ia(&lease->ia); + + free(lease->dns); + + lease->domains = strv_free(lease->domains); + + free(lease->ntp); + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + free(lease); return NULL; } @@ -392,7 +403,7 @@ int dhcp6_lease_new(sd_dhcp6_lease **ret) { if (!lease) return -ENOMEM; - lease->n_ref = REFCNT_INIT; + lease->n_ref = 1; LIST_HEAD_INIT(lease->ia.addresses); diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c index 2f867e8562..e80232a7e0 100644 --- a/src/libsystemd-network/sd-icmp6-nd.c +++ b/src/libsystemd-network/sd-icmp6-nd.c @@ -25,7 +25,6 @@ #include <sys/ioctl.h> #include "socket-util.h" -#include "refcnt.h" #include "async.h" #include "dhcp6-internal.h" @@ -47,7 +46,7 @@ enum icmp6_nd_state { typedef struct ICMP6Prefix ICMP6Prefix; struct ICMP6Prefix { - RefCount n_ref; + unsigned n_ref; LIST_FIELDS(ICMP6Prefix, prefixes); @@ -57,7 +56,7 @@ struct ICMP6Prefix { }; struct sd_icmp6_nd { - RefCount n_ref; + unsigned n_ref; enum icmp6_nd_state state; sd_event *event; @@ -78,13 +77,18 @@ struct sd_icmp6_nd { #define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__) static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) { - if (prefix && REFCNT_DEC(prefix->n_ref) <= 0) { - prefix->timeout_valid = - sd_event_source_unref(prefix->timeout_valid); - free(prefix); - } + if (!prefix) + return NULL; + + assert(prefix->n_ref > 0); + prefix->n_ref--; + if (prefix->n_ref > 0) + return NULL; + + prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid); + free(prefix); return NULL; } @@ -97,7 +101,7 @@ static int icmp6_prefix_new(ICMP6Prefix **ret) { if (!prefix) return -ENOMEM; - prefix->n_ref = REFCNT_INIT; + prefix->n_ref = 1; LIST_INIT(prefixes, prefix); *ret = prefix; @@ -106,8 +110,7 @@ static int icmp6_prefix_new(ICMP6Prefix **ret) { return 0; } -static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) -{ +static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) { if (nd->callback) nd->callback(nd, event, nd->userdata); } @@ -177,9 +180,12 @@ sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) { } sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) { - assert (nd); - assert_se(REFCNT_INC(nd->n_ref) >= 2); + if (!nd) + return NULL; + + assert(nd->n_ref > 0); + nd->n_ref++; return nd; } @@ -195,21 +201,28 @@ static int icmp6_nd_init(sd_icmp6_nd *nd) { } sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) { - if (nd && REFCNT_DEC(nd->n_ref) == 0) { - ICMP6Prefix *prefix, *p; + ICMP6Prefix *prefix, *p; - icmp6_nd_init(nd); - sd_icmp6_nd_detach_event(nd); + if (!nd) + return NULL; - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - LIST_REMOVE(prefixes, nd->prefixes, prefix); + assert(nd->n_ref > 0); + nd->n_ref--; - prefix = icmp6_prefix_unref(prefix); - } + if (nd->n_ref > 0) + return NULL; + + icmp6_nd_init(nd); + sd_icmp6_nd_detach_event(nd); - free(nd); + LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { + LIST_REMOVE(prefixes, nd->prefixes, prefix); + + prefix = icmp6_prefix_unref(prefix); } + free(nd); + return NULL; } @@ -225,7 +238,7 @@ int sd_icmp6_nd_new(sd_icmp6_nd **ret) { if (!nd) return -ENOMEM; - nd->n_ref = REFCNT_INIT; + nd->n_ref = 1; nd->index = -1; nd->fd = -1; @@ -376,9 +389,7 @@ int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, return 0; } -int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, - uint8_t *prefixlen) -{ +int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) { assert_return(nd, -EINVAL); assert_return(addr, -EINVAL); assert_return(prefixlen, -EINVAL); @@ -525,9 +536,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, return 0; } -static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, - uint32_t revents, void *userdata) -{ +static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_icmp6_nd *nd = userdata; int r, buflen = 0; ssize_t len; @@ -586,9 +595,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, return 0; } -static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, - void *userdata) -{ +static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_icmp6_nd *nd = userdata; uint64_t time_now, next_timeout; struct ether_addr unset = { }; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index f080c5c0a7..0fc05e1484 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -26,7 +26,6 @@ #include "util.h" #include "siphash24.h" #include "list.h" -#include "refcnt.h" #include "random-util.h" #include "ipv4ll-internal.h" @@ -68,7 +67,7 @@ typedef enum IPv4LLState { } IPv4LLState; struct sd_ipv4ll { - RefCount n_ref; + unsigned n_ref; IPv4LLState state; int index; @@ -598,30 +597,39 @@ int sd_ipv4ll_stop(sd_ipv4ll *ll) { } sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { - if (ll) - assert_se(REFCNT_INC(ll->n_ref) >= 2); + + if (!ll) + return NULL; + + assert(ll->n_ref >= 1); + ll->n_ref++; return ll; } sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { - if (ll && REFCNT_DEC(ll->n_ref) == 0) { - ll->receive_message = - sd_event_source_unref(ll->receive_message); - ll->fd = safe_close(ll->fd); - ll->timer = sd_event_source_unref(ll->timer); + if (!ll) + return NULL; - sd_ipv4ll_detach_event(ll); + assert(ll->n_ref >= 1); + ll->n_ref--; - free(ll->random_data); - free(ll->random_data_state); - free(ll); + if (ll->n_ref > 0) + return ll; - return NULL; - } + ll->receive_message = sd_event_source_unref(ll->receive_message); + ll->fd = safe_close(ll->fd); - return ll; + ll->timer = sd_event_source_unref(ll->timer); + + sd_ipv4ll_detach_event(ll); + + free(ll->random_data); + free(ll->random_data_state); + free(ll); + + return NULL; } DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref); @@ -636,7 +644,7 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { if (!ll) return -ENOMEM; - ll->n_ref = REFCNT_INIT; + ll->n_ref = 1; ll->state = IPV4LL_STATE_INIT; ll->index = -1; ll->fd = -1; diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c index ff064f563f..c6c9da812b 100644 --- a/src/libsystemd-network/sd-pppoe.c +++ b/src/libsystemd-network/sd-pppoe.c @@ -36,7 +36,6 @@ #include "random-util.h" #include "socket-util.h" #include "async.h" -#include "refcnt.h" #include "utf8.h" #define PPPOE_MAX_PACKET_SIZE 1484 @@ -68,7 +67,7 @@ typedef struct PPPoETags { } PPPoETags; struct sd_pppoe { - RefCount n_ref; + unsigned n_ref; PPPoEState state; uint64_t host_uniq; @@ -202,23 +201,34 @@ int sd_pppoe_detach_event(sd_pppoe *ppp) { } sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) { - if (ppp) - assert_se(REFCNT_INC(ppp->n_ref) >= 2); + + if (!ppp) + return NULL; + + assert(ppp->n_ref > 0); + ppp->n_ref++; return ppp; } sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) { - if (ppp && REFCNT_DEC(ppp->n_ref) <= 0) { - pppoe_tags_clear(&ppp->tags); - free(ppp->ifname); - free(ppp->service_name); - sd_pppoe_stop(ppp); - sd_pppoe_detach_event(ppp); - - free(ppp); - } + if (!ppp) + return NULL; + + assert(ppp->n_ref > 0); + ppp->n_ref--; + + if (ppp->n_ref > 0) + return NULL; + + pppoe_tags_clear(&ppp->tags); + free(ppp->ifname); + free(ppp->service_name); + sd_pppoe_stop(ppp); + sd_pppoe_detach_event(ppp); + + free(ppp); return NULL; } @@ -231,7 +241,7 @@ int sd_pppoe_new (sd_pppoe **ret) { if (!ppp) return -ENOMEM; - ppp->n_ref = REFCNT_INIT; + ppp->n_ref = 1; ppp->state = _PPPOE_STATE_INVALID; ppp->ifindex = -1; ppp->fd = -1; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 200499d613..29c20b77e3 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -43,16 +43,13 @@ static test_callback_recv_t callback_recv; static be32_t xid; static sd_event_source *test_hangcheck; -static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec, - void *userdata) -{ +static int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) { assert_not_reached("Test case should have completed in 2 seconds"); return 0; } -static void test_request_basic(sd_event *e) -{ +static void test_request_basic(sd_event *e) { int r; sd_dhcp_client *client; @@ -87,10 +84,7 @@ static void test_request_basic(sd_event *e) assert_se(sd_dhcp_client_set_request_option(client, DHCP_OPTION_DOMAIN_NAME) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_DOMAIN_NAME_SERVER) - == -EEXIST); - assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_NTP_SERVER) == -EEXIST); + DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, DHCP_OPTION_PAD) == -EINVAL); @@ -112,8 +106,7 @@ static void test_request_basic(sd_event *e) sd_dhcp_client_unref(client); } -static void test_checksum(void) -{ +static void test_checksum(void) { uint8_t buf[20] = { 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -126,9 +119,7 @@ static void test_checksum(void) assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae)); } -static int check_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) -{ +static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) { switch(code) { case DHCP_OPTION_CLIENT_IDENTIFIER: { @@ -141,10 +132,10 @@ static int check_options(uint8_t code, uint8_t len, const uint8_t *option, assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len); assert_se(len == 19); - assert_se(option[0] == 0xff); + assert_se(((uint8_t*) option)[0] == 0xff); - assert_se(memcmp(&option[1], &iaid, sizeof(iaid)) == 0); - assert_se(memcmp(&option[5], &duid, duid_len) == 0); + assert_se(memcmp((uint8_t*) option + 1, &iaid, sizeof(iaid)) == 0); + assert_se(memcmp((uint8_t*) option + 5, &duid, duid_len) == 0); break; } @@ -155,9 +146,7 @@ static int check_options(uint8_t code, uint8_t len, const uint8_t *option, return 0; } -int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, - const void *packet, size_t len) -{ +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len) { size_t size; _cleanup_free_ DHCPPacket *discover; uint16_t ip_check, udp_check; @@ -202,18 +191,20 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, return 575; } -int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, - uint32_t id, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) -{ +int dhcp_network_bind_raw_socket( + int index, + union sockaddr_union *link, + uint32_t id, + const uint8_t *addr, size_t addr_len, + uint16_t arp_type) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0) return -errno; return test_fd[0]; } -int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) -{ +int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { int fd; fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); @@ -223,14 +214,11 @@ int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) return fd; } -int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, - const void *packet, size_t len) -{ +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const void *packet, size_t len) { return 0; } -static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) -{ +static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) { int res; res = dhcp_option_parse(dhcp, size, check_options, NULL); @@ -242,8 +230,7 @@ static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) return 0; } -static void test_discover_message(sd_event *e) -{ +static void test_discover_message(sd_event *e) { sd_dhcp_client *client; int res, r; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index a63a4ea738..b1ef174849 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -145,8 +145,8 @@ static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) { } } -static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option, void *user_data) { - struct option_desc *desc = user_data; +static int test_options_cb(uint8_t code, uint8_t len, const void *option, void *userdata) { + struct option_desc *desc = userdata; uint8_t *descoption = NULL; int *desclen = NULL, *descpos = NULL; uint8_t optcode = 0; @@ -207,10 +207,10 @@ static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option, voi for (i = 0; i < len; i++) { if (verbose) - printf("0x%02x(0x%02x) ", option[i], + printf("0x%02x(0x%02x) ", ((uint8_t*) option)[i], descoption[*descpos + 2 + i]); - assert_se(option[i] == descoption[*descpos + 2 + i]); + assert_se(((uint8_t*) option)[i] == descoption[*descpos + 2 + i]); } if (verbose) diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 6e62262443..12daac3211 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -501,8 +501,7 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, return 0; } -static int test_client_send_advertise(DHCP6Message *solicit) -{ +static int test_client_send_advertise(DHCP6Message *solicit) { DHCP6Message advertise; advertise.transaction_id = solicit->transaction_id; diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index 5677bfb2d2..d60ee98b25 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -39,9 +39,9 @@ static int test_fd[2]; static int basic_request_handler_bind = 0; static int basic_request_handler_stop = 0; -static void* basic_request_handler_user_data = (void*)0xCABCAB; +static void* basic_request_handler_userdata = (void*)0xCABCAB; static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) { - assert_se(userdata == basic_request_handler_user_data); + assert_se(userdata == basic_request_handler_userdata); switch(event) { case IPV4LL_EVENT_STOP: @@ -175,7 +175,7 @@ static void test_basic_request(sd_event *e) { assert_se(sd_ipv4ll_start(ll) == -EINVAL); assert_se(sd_ipv4ll_set_callback(ll, basic_request_handler, - basic_request_handler_user_data) == 0); + basic_request_handler_userdata) == 0); assert_se(sd_ipv4ll_start(ll) == -EINVAL); assert_se(sd_ipv4ll_set_index(ll, 1) == 0); diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index a21ed8cb62..366a026426 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1024,7 +1024,9 @@ _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) { _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { assert_return(m, NULL); - assert_return(sd_bus_error_is_set(&m->error), NULL); + + if (!sd_bus_error_is_set(&m->error)) + return NULL; return &m->error; } diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index 40aa77ee5c..06c98314e8 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -79,8 +79,7 @@ static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) { return true; } -static bool linebuf_add_char(struct linebuf *buf, char c) -{ +static bool linebuf_add_char(struct linebuf *buf, char c) { if (buf->len + 1 >= sizeof(buf->bytes)) return false; buf->bytes[buf->len++] = c; @@ -269,13 +268,13 @@ static int trie_search_f(sd_hwdb *hwdb, const char *search) { } static const char hwdb_bin_paths[] = - "/etc/systemd/hwdb/hwdb.bin\0" - "/etc/udev/hwdb.bin\0" - "/usr/lib/systemd/hwdb/hwdb.bin\0" + "/etc/systemd/hwdb/hwdb.bin\0" + "/etc/udev/hwdb.bin\0" + "/usr/lib/systemd/hwdb/hwdb.bin\0" #ifdef HAVE_SPLIT_USR - "/lib/systemd/hwdb/hwdb.bin\0" + "/lib/systemd/hwdb/hwdb.bin\0" #endif - UDEVLIBEXECDIR "/hwdb.bin\0"; + UDEVLIBEXECDIR "/hwdb.bin\0"; _public_ int sd_hwdb_new(sd_hwdb **ret) { _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index b63fdf8fcb..87d87359b8 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -214,6 +214,28 @@ _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { return 0; } +int sd_network_link_get_timezone(int ifindex, char **ret) { + _cleanup_free_ char *s = NULL, *p = NULL; + int r; + + assert_return(ifindex > 0, -EINVAL); + assert_return(ret, -EINVAL); + + if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "TIMEZONE", &s, NULL); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + if (isempty(s)) + return -ENODATA; + + *ret = s; + s = NULL; + return 0; +} static int network_get_link_strv(const char *key, int ifindex, char ***ret) { _cleanup_free_ char *p = NULL, *s = NULL; diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index b0dc822591..888b372c99 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -48,9 +48,6 @@ typedef enum { RESPONSE_ADDRINFO, REQUEST_NAMEINFO, RESPONSE_NAMEINFO, - REQUEST_RES_QUERY, - REQUEST_RES_SEARCH, - RESPONSE_RES, REQUEST_TERMINATE, RESPONSE_DIED } QueryType; @@ -104,12 +101,10 @@ struct sd_resolve_query { int _h_errno; struct addrinfo *addrinfo; char *serv, *host; - unsigned char *answer; union { sd_resolve_getaddrinfo_handler_t getaddrinfo_handler; sd_resolve_getnameinfo_handler_t getnameinfo_handler; - sd_resolve_res_handler_t res_handler; }; void *userdata; @@ -166,33 +161,16 @@ typedef struct NameInfoResponse { int _h_errno; } NameInfoResponse; -typedef struct ResRequest { - struct RHeader header; - int class; - int type; - size_t dname_len; -} ResRequest; - -typedef struct ResResponse { - struct RHeader header; - int ret; - int _errno; - int _h_errno; -} ResResponse; - typedef union Packet { RHeader rheader; AddrInfoRequest addrinfo_request; AddrInfoResponse addrinfo_response; NameInfoRequest nameinfo_request; NameInfoResponse nameinfo_response; - ResRequest res_request; - ResResponse res_response; } Packet; static int getaddrinfo_done(sd_resolve_query* q); static int getnameinfo_done(sd_resolve_query *q); -static int res_query_done(sd_resolve_query* q); static void resolve_query_disconnect(sd_resolve_query *q); @@ -343,38 +321,6 @@ static int send_nameinfo_reply( return 0; } -static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret, int _errno, int _h_errno) { - - ResResponse resp = { - .header.type = RESPONSE_RES, - .header.id = id, - .ret = ret, - ._errno = _errno, - ._h_errno = _h_errno, - }; - - struct msghdr mh = {}; - struct iovec iov[2]; - size_t l; - - assert(out_fd >= 0); - - l = ret > 0 ? (size_t) ret : 0; - - resp.header.length = sizeof(ResResponse) + l; - - iov[0] = (struct iovec) { .iov_base = &resp, .iov_len = sizeof(ResResponse) }; - iov[1] = (struct iovec) { .iov_base = (void*) answer, .iov_len = l }; - - mh.msg_iov = iov; - mh.msg_iovlen = ELEMENTSOF(iov); - - if (sendmsg(out_fd, &mh, MSG_NOSIGNAL) < 0) - return -errno; - - return 0; -} - static int handle_request(int out_fd, const Packet *packet, size_t length) { const RHeader *req; @@ -437,29 +383,6 @@ static int handle_request(int out_fd, const Packet *packet, size_t length) { errno, h_errno); } - case REQUEST_RES_QUERY: - case REQUEST_RES_SEARCH: { - const ResRequest *res_req = &packet->res_request; - union { - HEADER header; - uint8_t space[BUFSIZE]; - } answer; - const char *dname; - int ret; - - assert(length >= sizeof(ResRequest)); - assert(length == sizeof(ResRequest) + res_req->dname_len); - - dname = (const char *) res_req + sizeof(ResRequest); - - if (req->type == REQUEST_RES_QUERY) - ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); - else - ret = res_search(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE); - - return send_res_reply(out_fd, req->id, (unsigned char *) &answer, ret, errno, h_errno); - } - case REQUEST_TERMINATE: /* Quit */ return -ECONNRESET; @@ -752,11 +675,6 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) { r = getnameinfo_done(q); break; - case REQUEST_RES_QUERY: - case REQUEST_RES_SEARCH: - r = res_query_done(q); - break; - default: assert_not_reached("Cannot complete unknown query type"); } @@ -923,28 +841,6 @@ static int handle_response(sd_resolve *resolve, const Packet *packet, size_t len return complete_query(resolve, q); } - case RESPONSE_RES: { - const ResResponse *res_resp = &packet->res_response; - - assert(length >= sizeof(ResResponse)); - assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH); - - q->ret = res_resp->ret; - q->_errno = res_resp->_errno; - q->_h_errno = res_resp->_h_errno; - - if (res_resp->ret >= 0) { - q->answer = memdup((const char *)resp + sizeof(ResResponse), res_resp->ret); - if (!q->answer) { - q->ret = -1; - q->_errno = ENOMEM; - q->_h_errno = 0; - } - } - - return complete_query(resolve, q); - } - default: return 0; } @@ -1181,79 +1077,6 @@ static int getnameinfo_done(sd_resolve_query *q) { return q->getnameinfo_handler(q, q->ret, q->host, q->serv, q->userdata); } -static int resolve_res( - sd_resolve *resolve, - sd_resolve_query **_q, - QueryType qtype, - const char *dname, - int class, int type, - sd_resolve_res_handler_t callback, void *userdata) { - - struct msghdr mh = {}; - struct iovec iov[2]; - ResRequest req = {}; - sd_resolve_query *q; - int r; - - assert_return(resolve, -EINVAL); - assert_return(dname, -EINVAL); - assert_return(callback, -EINVAL); - assert_return(!resolve_pid_changed(resolve), -ECHILD); - - r = alloc_query(resolve, !_q, &q); - if (r < 0) - return r; - - q->type = qtype; - q->res_handler = callback; - q->userdata = userdata; - - req.dname_len = strlen(dname) + 1; - req.class = class; - req.type = type; - - req.header.id = q->id; - req.header.type = qtype; - req.header.length = sizeof(ResRequest) + req.dname_len; - - iov[0] = (struct iovec) { .iov_base = &req, .iov_len = sizeof(ResRequest) }; - iov[1] = (struct iovec) { .iov_base = (void*) dname, .iov_len = req.dname_len }; - - mh.msg_iov = iov; - mh.msg_iovlen = 2; - - if (sendmsg(resolve->fds[REQUEST_SEND_FD], &mh, MSG_NOSIGNAL) < 0) { - sd_resolve_query_unref(q); - return -errno; - } - - resolve->n_outstanding++; - - if (_q) - *_q = q; - - return 0; -} - -_public_ int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) { - return resolve_res(resolve, q, REQUEST_RES_QUERY, dname, class, type, callback, userdata); -} - -_public_ int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query** q, const char *dname, int class, int type, sd_resolve_res_handler_t callback, void *userdata) { - return resolve_res(resolve, q, REQUEST_RES_SEARCH, dname, class, type, callback, userdata); -} - -static int res_query_done(sd_resolve_query* q) { - assert(q); - assert(q->done); - assert(q->res_handler); - - errno = q->_errno; - h_errno = q->_h_errno; - - return q->res_handler(q, q->ret, q->answer, q->userdata); -} - _public_ sd_resolve_query* sd_resolve_query_ref(sd_resolve_query *q) { assert_return(q, NULL); @@ -1310,7 +1133,6 @@ static void resolve_query_free(sd_resolve_query *q) { resolve_freeaddrinfo(q->addrinfo); free(q->host); free(q->serv); - free(q->answer); free(q); } diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index 354a4071b7..e8056529f5 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -67,59 +67,8 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c return 0; } -static int res_handler(sd_resolve_query *q, int ret, unsigned char *answer, void *userdata) { - int qdcount, ancount, len; - const unsigned char *pos = answer + sizeof(HEADER); - unsigned char *end = answer + ret; - HEADER *head = (HEADER *) answer; - char name[256]; - assert_se(q); - - if (ret < 0) { - log_error("res_query() error: %s %i", strerror(errno), errno); - return 0; - } - - if (ret == 0) { - log_error("No reply for SRV lookup"); - return 0; - } - - qdcount = ntohs(head->qdcount); - ancount = ntohs(head->ancount); - - printf("%d answers for srv lookup:\n", ancount); - - /* Ignore the questions */ - while (qdcount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) { - assert_se(len >= 0); - pos += len + QFIXEDSZ; - } - - /* Parse the answers */ - while (ancount-- > 0 && (len = dn_expand(answer, end, pos, name, 255)) >= 0) { - /* Ignore the initial string */ - uint16_t pref, weight, port; - assert_se(len >= 0); - pos += len; - /* Ignore type, ttl, class and dlen */ - pos += 10; - - GETSHORT(pref, pos); - GETSHORT(weight, pos); - GETSHORT(port, pos); - len = dn_expand(answer, end, pos, name, 255); - printf("\tpreference: %2d weight: %2d port: %d host: %s\n", - pref, weight, port, name); - - pos += len; - } - - return 0; -} - int main(int argc, char *argv[]) { - _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL, *q3 = NULL; + _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL; _cleanup_resolve_unref_ sd_resolve *resolve = NULL; int r = 0; @@ -150,15 +99,9 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "sd_resolve_getnameinfo(): %m"); - /* Make a res_query() call */ - r = sd_resolve_res_query(resolve, &q3, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV, res_handler, NULL); - if (r < 0) - log_error_errno(r, "sd_resolve_res_query(): %m"); - - /* Wait until the three queries are completed */ + /* Wait until the two queries are completed */ while (sd_resolve_query_is_done(q1) == 0 || - sd_resolve_query_is_done(q2) == 0 || - sd_resolve_query_is_done(q3) == 0) { + sd_resolve_query_is_done(q2) == 0) { r = sd_resolve_wait(resolve, (uint64_t) -1); if (r < 0) { diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 926035d185..8bd0ed756b 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -361,8 +361,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { bus, "org.freedesktop.systemd1", path, - endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : - endswith(unit, ".slice") ? "org.freedesktop.systemd1.Slice" : "org.freedesktop.systemd1.Service", + unit_dbus_interface_from_name(unit), "ControlGroup", &error, &reply, diff --git a/src/network/networkctl.c b/src/network/networkctl.c index c9b53dc3f6..2281d4b718 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -497,7 +497,7 @@ static int link_status_one( sd_hwdb *hwdb, const char *name) { _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; - _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; + _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *timezone = NULL; _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; _cleanup_device_unref_ sd_device *d = NULL; char devid[2 + DECIMAL_STR_MAX(int)]; @@ -570,7 +570,6 @@ static int link_status_one( setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); sd_network_link_get_dns(ifindex, &dns); - sd_network_link_get_ntp(ifindex, &ntp); sd_network_link_get_domains(ifindex, &domains); r = sd_network_link_get_wildcard_domain(ifindex); if (r > 0) { @@ -652,6 +651,8 @@ static int link_status_one( dump_list(" DNS: ", dns); if (!strv_isempty(domains)) dump_list(" Domain: ", domains); + + (void) sd_network_link_get_ntp(ifindex, &ntp); if (!strv_isempty(ntp)) dump_list(" NTP: ", ntp); @@ -661,6 +662,10 @@ static int link_status_one( if (!strv_isempty(carrier_bound_by)) dump_list("Carrier Bound By: ", carrier_bound_by); + (void) sd_network_link_get_timezone(ifindex, &timezone); + if (timezone) + printf(" Time Zone: %s", timezone); + return 0; } diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index 584a956a7e..d609daafde 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -19,9 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "networkd.h" -#include "networkd-link.h" +#include "networkd-address-pool.h" int address_pool_new( Manager *m, diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h new file mode 100644 index 0000000000..e6207ccce6 --- /dev/null +++ b/src/network/networkd-address-pool.h @@ -0,0 +1,43 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +typedef struct AddressPool AddressPool; + +#include "networkd.h" + +struct AddressPool { + Manager *manager; + + int family; + unsigned prefixlen; + + union in_addr_union in_addr; + + LIST_FIELDS(AddressPool, address_pools); +}; + +int address_pool_new(Manager *m, AddressPool **ret, int family, const union in_addr_union *u, unsigned prefixlen); +int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen); +void address_pool_free(AddressPool *p); + +int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 172ca43a7d..b0d296941e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -25,8 +25,10 @@ #include "util.h" #include "conf-parser.h" #include "firewall-util.h" +#include "netlink-util.h" + #include "networkd.h" -#include "networkd-link.h" +#include "networkd-address.h" static void address_init(Address *address) { assert(address); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h new file mode 100644 index 0000000000..39789a2382 --- /dev/null +++ b/src/network/networkd-address.h @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include "in-addr-util.h" + +typedef struct Address Address; + +#include "networkd.h" +#include "networkd-network.h" +#include "networkd-link.h" + +#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU + +struct Address { + Network *network; + unsigned section; + + int family; + unsigned char prefixlen; + unsigned char scope; + uint32_t flags; + char *label; + + struct in_addr broadcast; + struct ifa_cacheinfo cinfo; + + union in_addr_union in_addr; + union in_addr_union in_addr_peer; + + bool ip_masquerade_done; + + LIST_FIELDS(Address, addresses); +}; + +int address_new_static(Network *network, unsigned section, Address **ret); +int address_new_dynamic(Address **ret); +void address_free(Address *address); +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_establish(Address *address, Link *link); +int address_release(Address *address, Link *link); +bool address_equal(Address *a1, Address *a2); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); +#define _cleanup_address_free_ _cleanup_(address_freep) + +int config_parse_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_broadcast(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 1b2ff7c769..36601367bf 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -39,8 +39,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set DHCPv4 route: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv4 route: %m"); link_enter_failed(link); } @@ -61,40 +60,25 @@ static int link_set_dhcp_routes(Link *link) { assert(link->dhcp_lease); r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); - if (r < 0 && r != -ENOENT) { - log_link_warning(link, - "DHCP error: could not get gateway: %s", - strerror(-r)); - return r; - } + if (r < 0 && r != -ENOENT) + return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); + if (r >= 0) { struct in_addr address; _cleanup_route_free_ Route *route = NULL; _cleanup_route_free_ Route *route_gw = NULL; r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); - if (r < 0) { - log_link_warning(link, - "DHCP error: could not get address: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: could not get address: %m"); r = route_new_dynamic(&route, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, - "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); r = route_new_dynamic(&route_gw, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, - "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); /* The dhcp netmask may mask out the gateway. Add an explicit * route for the gw host so that we can route no matter the @@ -107,12 +91,8 @@ static int link_set_dhcp_routes(Link *link) { route_gw->metrics = link->network->dhcp_route_metric; r = route_configure(route_gw, link, &dhcp4_route_handler); - if (r < 0) { - log_link_warning(link, - "could not set host route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages ++; @@ -123,9 +103,7 @@ static int link_set_dhcp_routes(Link *link) { r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) { - log_link_warning(link, - "could not set routes: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not set routes: %m"); link_enter_failed(link); return r; } @@ -136,23 +114,15 @@ static int link_set_dhcp_routes(Link *link) { n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); if (n == -ENOENT) return 0; - if (n < 0) { - log_link_warning(link, - "DHCP error: could not get routes: %s", - strerror(-n)); - - return n; - } + if (n < 0) + return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m"); for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; r = route_new_dynamic(&route, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; route->in_addr.in = static_routes[i].gw_addr; @@ -161,12 +131,8 @@ static int link_set_dhcp_routes(Link *link) { route->metrics = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); - if (r < 0) { - log_link_warning(link, - "could not set host route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages ++; } @@ -270,18 +236,16 @@ static int dhcp_lease_lost(Link *link) { if (link->network->dhcp_hostname) { const char *hostname = NULL; - if (!link->network->hostname) - r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); - else + if (link->network->hostname) hostname = link->network->hostname; + else + (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); - if (r >= 0 || hostname) { - r = link_set_hostname(link, hostname); + if (hostname) { + /* If a hostname was set due to the lease, then unset it now. */ + r = link_set_hostname(link, NULL); if (r < 0) - log_link_error_errno(link, r, - "Failed to set transient hostname to '%s': %m", - hostname); - + log_link_warning_errno(link, r, "Failed to reset transient hostname: %m"); } } @@ -300,8 +264,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set DHCPv4 address: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv4 address: %m"); link_enter_failed(link); } else if (r >= 0) link_rtnl_process_address(rtnl, m, link->manager); @@ -357,45 +320,30 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { assert(link->network); r = sd_dhcp_client_get_lease(client, &lease); - if (r < 0) { - log_link_warning(link, "DHCP error: no lease %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no lease: %m"); sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp4_configured = false; link->dhcp_lease = sd_dhcp_lease_ref(lease); r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) { - log_link_warning(link, "DHCP error: no address: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no address: %m"); r = sd_dhcp_lease_get_netmask(lease, &netmask); - if (r < 0) { - log_link_warning(link, "DHCP error: no netmask: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no netmask: %m"); if (!link->network->dhcp_critical) { - r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, - &lifetime); - if (r < 0) { - log_link_warning(link, - "DHCP error: no lifetime: %s", - strerror(-r)); - return r; - } + r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m"); } r = dhcp4_update_address(link, &address, &netmask, lifetime); if (r < 0) { - log_link_warning(link, "could not update IP address: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not update IP address: %m"); link_enter_failed(link); return r; } @@ -417,21 +365,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { r = sd_dhcp_client_get_lease(client, &lease); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no lease: %m"); + return log_link_error_errno(link, r, "DHCP error: No lease: %m"); r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no address: %m"); + return log_link_error_errno(link, r, "DHCP error: No address: %m"); r = sd_dhcp_lease_get_netmask(lease, &netmask); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no netmask: %m"); + return log_link_error_errno(link, r, "DHCP error: No netmask: %m"); prefixlen = in_addr_netmask_to_prefixlen(&netmask); r = sd_dhcp_lease_get_router(lease, &gateway); if (r < 0 && r != -ENOENT) - return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m"); + return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); if (r >= 0) log_struct(LOG_INFO, @@ -470,18 +418,30 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { if (link->network->dhcp_hostname) { const char *hostname = NULL; - if (!link->network->hostname) - r = sd_dhcp_lease_get_hostname(lease, &hostname); - else + if (link->network->hostname) hostname = link->network->hostname; + else + (void) sd_dhcp_lease_get_hostname(lease, &hostname); - if (r >= 0 || hostname) { + if (hostname) { r = link_set_hostname(link, hostname); if (r < 0) log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); } } + if (link->network->dhcp_timezone) { + const char *tz = NULL; + + (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); + + if (tz) { + r = link_set_timezone(link, tz); + if (r < 0) + log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz); + } + } + if (!link->network->dhcp_critical) { r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); if (r < 0) { @@ -515,8 +475,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { case DHCP_EVENT_STOP: case DHCP_EVENT_IP_CHANGE: if (link->network->dhcp_critical) { - log_link_error(link, - "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); + log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); return; } @@ -553,13 +512,9 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { break; default: if (event < 0) - log_link_warning(link, - "DHCP error: client failed: %s", - strerror(-event)); + log_link_warning_errno(link, event, "DHCP error: Client failed: %m"); else - log_link_warning(link, - "DHCP unknown event: %d", - event); + log_link_warning(link, "DHCP unknown event: %i", event); break; } @@ -607,10 +562,10 @@ int dhcp4_configure(Link *link) { } if (link->network->dhcp_mtu) { - r = sd_dhcp_client_set_request_option(link->dhcp_client, - DHCP_OPTION_INTERFACE_MTU); - if (r < 0) - return r; + r = sd_dhcp_client_set_request_option(link->dhcp_client, + DHCP_OPTION_INTERFACE_MTU); + if (r < 0) + return r; } if (link->network->dhcp_routes) { @@ -624,6 +579,15 @@ int dhcp4_configure(Link *link) { return r; } + /* Always acquire the timezone and NTP*/ + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NTP_SERVER); + if (r < 0) + return r; + + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE); + if (r < 0) + return r; + if (link->network->dhcp_sendhost) { _cleanup_free_ char *hostname = NULL; const char *hn = NULL; diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 0f2510e904..22efadb843 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -22,10 +22,12 @@ #include <net/if.h> #include <net/ethernet.h> -#include "networkd.h" -#include "networkd-link.h" #include "conf-parser.h" #include "util.h" +#include "netlink-util.h" + +#include "networkd.h" +#include "networkd-fdb.h" /* create a new FDB entry or get an existing one. */ int fdb_entry_new_static(Network *const network, diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h new file mode 100644 index 0000000000..f0efb902d0 --- /dev/null +++ b/src/network/networkd-fdb.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +typedef struct FdbEntry FdbEntry; + +#include "networkd.h" +#include "networkd-network.h" + +struct FdbEntry { + Network *network; + unsigned section; + + struct ether_addr *mac_addr; + uint16_t vlan_id; + + LIST_FIELDS(FdbEntry, static_fdb_entries); +}; + +int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret); +void fdb_entry_free(FdbEntry *fdb_entry); +int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free); +#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep) + +int config_parse_fdb_hwaddr(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_fdb_vlan_id(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index cc9dc393c6..ff693ed0fd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -29,7 +29,10 @@ #include "socket-util.h" #include "bus-util.h" #include "udev-util.h" +#include "netlink-util.h" +#include "dhcp-lease-internal.h" #include "network-internal.h" + #include "networkd-link.h" #include "networkd-netdev.h" @@ -613,6 +616,96 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda return 1; } +static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + log_debug("Copying DNS server information from %s", link->ifname); + + if (!link->network) + return 0; + + STRV_FOREACH(a, link->network->dns) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_dns && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_dns(s, addresses, n_addresses); +} + +static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + if (!link->network) + return 0; + + log_debug("Copying NTP server information from %s", link->ifname); + + STRV_FOREACH(a, link->network->ntp) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_ntp && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_ntp(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_ntp(s, addresses, n_addresses); +} + static int link_enter_set_addresses(Link *link) { Address *ad; int r; @@ -639,6 +732,8 @@ static int link_enter_set_addresses(Link *link) { if (link_dhcp4_server_enabled(link)) { struct in_addr pool_start; Address *address; + Link *uplink = NULL; + bool acquired_uplink = false; address = link_find_dhcp_server_address(link); if (!address) { @@ -672,6 +767,81 @@ static int link_enter_set_addresses(Link *link) { return r; */ + if (link->network->dhcp_server_max_lease_time_usec > 0) { + r = sd_dhcp_server_set_max_lease_time( + link->dhcp_server, + DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC)); + if (r < 0) + return r; + } + + if (link->network->dhcp_server_default_lease_time_usec > 0) { + r = sd_dhcp_server_set_default_lease_time( + link->dhcp_server, + DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC)); + if (r < 0) + return r; + } + + if (link->network->dhcp_server_emit_dns) { + + if (link->network->n_dhcp_server_dns > 0) + r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns); + else { + uplink = manager_find_uplink(link->manager, link); + acquired_uplink = true; + + if (!uplink) { + log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server); + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m"); + } + + + if (link->network->dhcp_server_emit_ntp) { + + if (link->network->n_dhcp_server_ntp > 0) + r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp); + else { + if (!acquired_uplink) + uplink = manager_find_uplink(link->manager, link); + + if (!uplink) { + log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server); + + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); + } + + if (link->network->dhcp_server_emit_timezone) { + _cleanup_free_ char *buffer = NULL; + const char *tz; + + if (link->network->dhcp_server_timezone) + tz = link->network->dhcp_server_timezone; + else { + r = get_timezone(&buffer); + if (r < 0) + log_warning_errno(r, "Failed to determine timezone: %m"); + else + tz = buffer; + } + + if (tz) { + r = sd_dhcp_server_set_timezone(link->dhcp_server, tz); + if (r < 0) + return r; + } + } + r = sd_dhcp_server_start(link->dhcp_server); if (r < 0) { log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m"); @@ -743,7 +913,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { _cleanup_link_unref_ Link *link = userdata; - int r; + const sd_bus_error *e; assert(m); assert(link); @@ -751,21 +921,20 @@ static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; - r = sd_bus_message_get_errno(m); - if (r > 0) - log_link_warning_errno(link, r, "Could not set hostname: %m"); + e = sd_bus_message_get_error(m); + if (e) + log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message); return 1; } int link_set_hostname(Link *link, const char *hostname) { - int r = 0; + int r; assert(link); assert(link->manager); - assert(hostname); - log_link_debug(link, "Setting transient hostname: '%s'", hostname); + log_link_debug(link, "Setting transient hostname: '%s'", strna(hostname)); if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */ @@ -794,6 +963,57 @@ int link_set_hostname(Link *link, const char *hostname) { return 0; } +static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + _cleanup_link_unref_ Link *link = userdata; + const sd_bus_error *e; + + assert(m); + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + e = sd_bus_message_get_error(m); + if (e) + log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message); + + return 1; +} + +int link_set_timezone(Link *link, const char *timezone) { + int r; + + assert(link); + assert(link->manager); + assert(timezone); + + log_link_debug(link, "Setting system timezone: '%s'", timezone); + + if (!link->manager->bus) { + log_link_info(link, "Not connected to system bus, ignoring timezone."); + return 0; + } + + r = sd_bus_call_method_async( + link->manager->bus, + NULL, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetTimezone", + set_timezone_handler, + link, + "sb", + timezone, + false); + if (r < 0) + return log_link_error_errno(link, r, "Could not set timezone: %m"); + + link_ref(link); + + return 0; +} + static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -2414,9 +2634,17 @@ int link_save(Link *link) { } if (link->dhcp_lease) { + const char *tz = NULL; + + r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); + if (r >= 0) + fprintf(f, "TIMEZONE=%s\n", tz); + } + + if (link->dhcp_lease) { assert(link->network); - r = sd_dhcp_lease_save(link->dhcp_lease, link->lease_file); + r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) goto fail; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 2dcbbda607..f588faf209 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once + /*** This file is part of systemd. @@ -19,11 +21,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <endian.h> -#include "networkd.h" +#include "sd-dhcp-client.h" +#include "sd-dhcp-server.h" +#include "sd-ipv4ll.h" +#include "sd-icmp6-nd.h" +#include "sd-dhcp6-client.h" +#include "sd-lldp.h" + +typedef struct Link Link; typedef enum LinkState { LINK_STATE_PENDING, @@ -38,6 +45,21 @@ typedef enum LinkState { _LINK_STATE_INVALID = -1 } LinkState; +typedef enum LinkOperationalState { + LINK_OPERSTATE_OFF, + LINK_OPERSTATE_NO_CARRIER, + LINK_OPERSTATE_DORMANT, + LINK_OPERSTATE_CARRIER, + LINK_OPERSTATE_DEGRADED, + LINK_OPERSTATE_ROUTABLE, + _LINK_OPERSTATE_MAX, + _LINK_OPERSTATE_INVALID = -1 +} LinkOperationalState; + +#include "networkd.h" +#include "networkd-network.h" +#include "networkd-address.h" + struct Link { Manager *manager; @@ -115,6 +137,7 @@ bool link_has_carrier(Link *link); int link_set_mtu(Link *link, uint32_t mtu); int link_set_hostname(Link *link, const char *hostname); +int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); @@ -130,6 +153,9 @@ bool link_dhcp6_enabled(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; +const char* link_operstate_to_string(LinkOperationalState s) _const_; +LinkOperationalState link_operstate_from_string(const char *s) _pure_; + extern const sd_bus_vtable link_vtable[]; int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 09a929e0da..16f732f244 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -22,20 +22,21 @@ #include <sys/socket.h> #include <linux/if.h> +#include "sd-netlink.h" +#include "sd-daemon.h" + #include "conf-parser.h" #include "path-util.h" -#include "networkd.h" -#include "networkd-netdev.h" -#include "networkd-link.h" #include "libudev-private.h" #include "udev-util.h" #include "netlink-util.h" #include "bus-util.h" #include "def.h" #include "virt.h" +#include "set.h" +#include "local-addresses.h" -#include "sd-netlink.h" -#include "sd-daemon.h" +#include "networkd.h" /* use 8 MB for receive socket kernel queue. */ #define RCVBUF_SIZE (8*1024*1024) @@ -99,7 +100,7 @@ static int manager_reset_all(Manager *m) { HASHMAP_FOREACH(link, m->links, i) { r = link_carrier_reset(link); if (r < 0) - log_link_warning_errno(link, r, "could not reset carrier: %m"); + log_link_warning_errno(link, r, "Could not reset carrier: %m"); } return 0; @@ -204,7 +205,7 @@ static int manager_udev_process_link(Manager *m, struct udev_device *device) { ifindex = udev_device_get_ifindex(device); if (ifindex <= 0) { - log_debug("ignoring udev ADD event for device with invalid ifindex"); + log_debug("Ignoring udev ADD event for device with invalid ifindex"); return 0; } @@ -291,23 +292,23 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa if (sd_netlink_message_is_error(message)) { r = sd_netlink_message_get_errno(message); if (r < 0) - log_warning_errno(r, "rtnl: could not receive link: %m"); + log_warning_errno(r, "rtnl: Could not receive link: %m"); return 0; } r = sd_netlink_message_get_type(message, &type); if (r < 0) { - log_warning_errno(r, "rtnl: could not get message type: %m"); + log_warning_errno(r, "rtnl: Could not get message type: %m"); return 0; } else if (type != RTM_NEWLINK && type != RTM_DELLINK) { - log_warning("rtnl: received unexpected message type when processing link"); + log_warning("rtnl: Received unexpected message type when processing link"); return 0; } r = sd_rtnl_message_link_get_ifindex(message, &ifindex); if (r < 0) { - log_warning_errno(r, "rtnl: could not get ifindex from link: %m"); + log_warning_errno(r, "rtnl: Could not get ifindex from link: %m"); return 0; } else if (ifindex <= 0) { log_warning("rtnl: received link message with invalid ifindex: %d", ifindex); @@ -317,7 +318,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); if (r < 0) { - log_warning_errno(r, "rtnl: received link message without ifname: %m"); + log_warning_errno(r, "rtnl: Received link message without ifname: %m"); return 0; } else netdev_get(m, name, &netdev); @@ -328,7 +329,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa /* link is new, so add it */ r = link_add(m, message, &link); if (r < 0) { - log_warning_errno(r, "could not add new link: %m"); + log_warning_errno(r, "Could not add new link: %m"); return 0; } } @@ -337,7 +338,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa /* netdev exists, so make sure the ifindex matches */ r = netdev_set_ifindex(netdev, message); if (r < 0) { - log_warning_errno(r, "could not set ifindex on netdev: %m"); + log_warning_errno(r, "Could not set ifindex on netdev: %m"); return 0; } } @@ -476,13 +477,13 @@ void manager_free(Manager *m) { free(m->state_file); + sd_event_source_unref(m->udev_event_source); udev_monitor_unref(m->udev_monitor); udev_unref(m->udev); + sd_bus_unref(m->bus); sd_bus_slot_unref(m->prepare_for_sleep_slot); - sd_event_source_unref(m->udev_event_source); sd_event_source_unref(m->bus_retry_event_source); - sd_event_unref(m->event); while ((link = hashmap_first(m->links))) link_unref(link); @@ -501,6 +502,7 @@ void manager_free(Manager *m) { address_pool_free(pool); sd_netlink_unref(m->rtnl); + sd_event_unref(m->event); free(m); } @@ -846,36 +848,39 @@ int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, uni return 0; } -const char *address_family_boolean_to_string(AddressFamilyBoolean b) { - if (b == ADDRESS_FAMILY_YES || - b == ADDRESS_FAMILY_NO) - return yes_no(b == ADDRESS_FAMILY_YES); +Link* manager_find_uplink(Manager *m, Link *exclude) { + _cleanup_free_ struct local_address *gateways = NULL; + int n, i; - if (b == ADDRESS_FAMILY_IPV4) - return "ipv4"; - if (b == ADDRESS_FAMILY_IPV6) - return "ipv6"; + assert(m); - return NULL; -} + /* Looks for a suitable "uplink", via black magic: an + * interface that is up and where the default route with the + * highest priority points to. */ -AddressFamilyBoolean address_family_boolean_from_string(const char *s) { - int r; + n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways); + if (n < 0) { + log_warning_errno(n, "Failed to determine list of default gateways: %m"); + return NULL; + } + + for (i = 0; i < n; i++) { + Link *link; + + link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex)); + if (!link) { + log_debug("Weird, found a gateway for a link we don't know. Ignoring."); + continue; + } - /* Make this a true superset of a boolean */ + if (link == exclude) + continue; - r = parse_boolean(s); - if (r > 0) - return ADDRESS_FAMILY_YES; - if (r == 0) - return ADDRESS_FAMILY_NO; + if (link->operstate < LINK_OPERSTATE_ROUTABLE) + continue; - if (streq(s, "ipv4")) - return ADDRESS_FAMILY_IPV4; - if (streq(s, "ipv6")) - return ADDRESS_FAMILY_IPV6; + return link; + } - return _ADDRESS_FAMILY_BOOLEAN_INVALID; + return NULL; } - -DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option"); diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h index 9991fa731f..0cdce1605e 100644 --- a/src/network/networkd-netdev-bond.h +++ b/src/network/networkd-netdev-bond.h @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once + /*** This file is part of systemd. @@ -19,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once +#include "in-addr-util.h" typedef struct Bond Bond; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index cd31387b41..ff1edf2c39 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -21,15 +21,18 @@ #include <net/if.h> -#include "networkd-netdev.h" -#include "networkd-link.h" -#include "network-internal.h" #include "conf-files.h" #include "conf-parser.h" #include "list.h" #include "siphash24.h" +#include "netlink-util.h" +#include "network-internal.h" + +#include "networkd.h" +#include "networkd-netdev.h" const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { + [NETDEV_KIND_BRIDGE] = &bridge_vtable, [NETDEV_KIND_BOND] = &bond_vtable, [NETDEV_KIND_VLAN] = &vlan_vtable, diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 19fb5bb185..1f8510c4f7 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -21,11 +21,14 @@ #pragma once -#include "networkd.h" #include "list.h" +typedef struct NetDev NetDev; typedef struct NetDevVTable NetDevVTable; +#include "networkd.h" +#include "networkd-link.h" + typedef struct netdev_join_callback netdev_join_callback; struct netdev_join_callback { diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 7ac7ef1ea3..108e892fb8 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -73,6 +73,15 @@ DHCP.RequestBroadcast, config_parse_bool, 0 DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) +DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone) +DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) +DHCPServer.DefaultLeaseTimeSec,config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) +DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) +DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0 +DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp) +DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 +DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) +DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu) Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 6587ea994c..2a77242013 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -26,11 +26,11 @@ #include "conf-parser.h" #include "util.h" #include "hostname-util.h" -#include "networkd.h" -#include "networkd-netdev.h" -#include "networkd-link.h" -#include "network-internal.h" #include "dns-domain.h" +#include "network-internal.h" + +#include "networkd.h" +#include "networkd-network.h" static int network_load_one(Manager *manager, const char *filename) { _cleanup_network_free_ Network *network = NULL; @@ -107,6 +107,10 @@ static int network_load_one(Manager *manager, const char *filename) { network->dhcp_route_metric = DHCP_ROUTE_METRIC; network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID; + network->dhcp_server_emit_dns = true; + network->dhcp_server_emit_ntp = true; + network->dhcp_server_emit_timezone = true; + network->use_bpdu = true; network->allow_port_to_be_root = true; network->unicast_flood = true; @@ -124,7 +128,8 @@ static int network_load_one(Manager *manager, const char *filename) { "Address\0" "Route\0" "DHCP\0" - "DHCPv4\0" + "DHCPv4\0" /* compat */ + "DHCPServer\0" "Bridge\0" "BridgeFDB\0", config_item_perf_lookup, network_network_gperf_lookup, @@ -258,6 +263,10 @@ void network_free(Network *network) { condition_free_list(network->match_kernel); condition_free_list(network->match_arch); + free(network->dhcp_server_timezone); + free(network->dhcp_server_dns); + free(network->dhcp_server_ntp); + free(network); } @@ -632,57 +641,6 @@ static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier); DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type"); -static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { - [RESOLVE_SUPPORT_NO] = "no", - [RESOLVE_SUPPORT_YES] = "yes", - [RESOLVE_SUPPORT_RESOLVE] = "resolve", -}; - -DEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport); - -int config_parse_resolve( - const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ResolveSupport *resolve = data; - int k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(resolve); - - /* Our enum shall be a superset of booleans, hence first try - * to parse as boolean, and then as enum */ - - k = parse_boolean(rvalue); - if (k > 0) - *resolve = RESOLVE_SUPPORT_YES; - else if (k == 0) - *resolve = RESOLVE_SUPPORT_NO; - else { - ResolveSupport s; - - s = resolve_support_from_string(rvalue); - if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s option, ignoring: %s", lvalue, rvalue); - return 0; - } - - *resolve = s; - } - - return 0; -} - int config_parse_ipv6token( const char* unit, const char *filename, @@ -726,40 +684,6 @@ int config_parse_ipv6token( return 0; } -int config_parse_address_family_boolean_with_kernel( - const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - AddressFamilyBoolean *fwd = data, s; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - s = address_family_boolean_from_string(rvalue); - if (s < 0) { - if (streq(rvalue, "kernel")) - s = _ADDRESS_FAMILY_BOOLEAN_INVALID; - else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue); - return 0; - } - } - - *fwd = s; - - return 0; -} - static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = { [IPV6_PRIVACY_EXTENSIONS_NO] = "no", [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public", @@ -816,37 +740,165 @@ int config_parse_ipv6_privacy_extensions( return 0; } -int config_parse_hostname(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - char **hostname = data; - char *hn = NULL; +int config_parse_hostname( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **hostname = data, *hn = NULL; int r; assert(filename); assert(lvalue); assert(rvalue); - r = config_parse_string(unit, filename, line, section, section_line, - lvalue, ltype, rvalue, &hn, userdata); + r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata); if (r < 0) return r; - if (!hostname_is_valid(hn, true)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "hostname is not valid, ignoring assignment: %s", rvalue); - + if (!hostname_is_valid(hn, false)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue); free(hn); return 0; } + free(*hostname); *hostname = hostname_cleanup(hn); + return 0; +} + +int config_parse_timezone( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **timezone = data, *tz = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata); + if (r < 0) + return r; + + if (!timezone_is_valid(tz)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue); + free(tz); + return 0; + } + + free(*timezone); + *timezone = tz; return 0; } + +int config_parse_dhcp_server_dns( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = data; + const char *p = rvalue; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); + return 0; + } + + if (r == 0) + return 0; + + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w); + continue; + } + + m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); + + m[n->n_dhcp_server_dns++] = a; + n->dhcp_server_dns = m; + } +} + +int config_parse_dhcp_server_ntp( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = data; + const char *p = rvalue; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, r, line, "Failed to extract word, ignoring: %s", rvalue); + return 0; + } + + if (r == 0) + return 0; + + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, r, line, "Failed to parse NTP server address, ignoring: %s", w); + continue; + } + + m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); + + m[n->n_dhcp_server_ntp++] = a; + n->dhcp_server_ntp = m; + } +} diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h new file mode 100644 index 0000000000..d691cc3a45 --- /dev/null +++ b/src/network/networkd-network.h @@ -0,0 +1,179 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "condition.h" + +typedef struct Network Network; + +#include "networkd.h" +#include "networkd-netdev.h" +#include "networkd-address.h" +#include "networkd-route.h" +#include "networkd-fdb.h" +#include "networkd-util.h" + +#define DHCP_ROUTE_METRIC 1024 +#define IPV4LL_ROUTE_METRIC 2048 + +typedef enum DCHPClientIdentifier { + DHCP_CLIENT_ID_MAC, + DHCP_CLIENT_ID_DUID, + _DHCP_CLIENT_ID_MAX, + _DHCP_CLIENT_ID_INVALID = -1, +} DCHPClientIdentifier; + +typedef enum IPv6PrivacyExtensions { + /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ + IPV6_PRIVACY_EXTENSIONS_NO, + IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, + IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ + _IPV6_PRIVACY_EXTENSIONS_MAX, + _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, +} IPv6PrivacyExtensions; + +struct Network { + Manager *manager; + + char *filename; + char *name; + + struct ether_addr *match_mac; + char **match_path; + char **match_driver; + char **match_type; + char **match_name; + + Condition *match_host; + Condition *match_virt; + Condition *match_kernel; + Condition *match_arch; + + char *description; + + NetDev *bridge; + NetDev *bond; + Hashmap *stacked_netdevs; + + /* DHCP Client Support */ + AddressFamilyBoolean dhcp; + DCHPClientIdentifier dhcp_client_identifier; + char *dhcp_vendor_class_identifier; + char *hostname; + bool dhcp_dns; + bool dhcp_ntp; + bool dhcp_mtu; + bool dhcp_hostname; + bool dhcp_domains; + bool dhcp_sendhost; + bool dhcp_broadcast; + bool dhcp_critical; + bool dhcp_routes; + bool dhcp_timezone; + unsigned dhcp_route_metric; + + /* DHCP Server Support */ + bool dhcp_server; + bool dhcp_server_emit_dns; + struct in_addr *dhcp_server_dns; + unsigned n_dhcp_server_dns; + bool dhcp_server_emit_ntp; + struct in_addr *dhcp_server_ntp; + unsigned n_dhcp_server_ntp; + bool dhcp_server_emit_timezone; + char *dhcp_server_timezone; + usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; + + /* IPV4LL Support */ + AddressFamilyBoolean link_local; + bool ipv4ll_route; + + /* Bridge Support */ + bool use_bpdu; + bool hairpin; + bool fast_leave; + bool allow_port_to_be_root; + bool unicast_flood; + unsigned cost; + + AddressFamilyBoolean ip_forward; + bool ip_masquerade; + + union in_addr_union ipv6_token; + IPv6PrivacyExtensions ipv6_privacy_extensions; + + struct ether_addr *mac; + unsigned mtu; + + bool lldp; + + LIST_HEAD(Address, static_addresses); + LIST_HEAD(Route, static_routes); + LIST_HEAD(FdbEntry, static_fdb_entries); + + Hashmap *addresses_by_section; + Hashmap *routes_by_section; + Hashmap *fdb_entries_by_section; + + bool wildcard_domain; + char **domains, **dns, **ntp, **bind_carrier; + + ResolveSupport llmnr; + + LIST_FIELDS(Network, networks); +}; + +void network_free(Network *network); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); +#define _cleanup_network_free_ _cleanup_(network_freep) + +int network_load(Manager *manager); + +int network_get_by_name(Manager *manager, const char *name, Network **ret); +int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret); +int network_apply(Manager *manager, Network *network, Link *link); + +int config_parse_netdev(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_tunnel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_client_identifier(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ipv6token(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +/* Legacy IPv4LL support */ +int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); + +extern const sd_bus_vtable network_vtable[]; + +int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int network_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); + +const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; +IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 31b10c458d..fbaad40579 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,12 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "networkd.h" -#include "networkd-link.h" - #include "util.h" #include "conf-parser.h" +#include "netlink-util.h" + +#include "networkd.h" +#include "networkd-route.h" int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h new file mode 100644 index 0000000000..d090b9c91e --- /dev/null +++ b/src/network/networkd-route.h @@ -0,0 +1,60 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +typedef struct Route Route; + +#include "networkd.h" +#include "networkd-network.h" + +struct Route { + Network *network; + unsigned section; + + int family; + unsigned char dst_prefixlen; + unsigned char src_prefixlen; + unsigned char scope; + uint32_t metrics; + unsigned char protocol; /* RTPROT_* */ + + union in_addr_union in_addr; + union in_addr_union dst_addr; + union in_addr_union src_addr; + union in_addr_union prefsrc_addr; + + LIST_FIELDS(Route, routes); +}; + +int route_new_static(Network *network, unsigned section, Route **ret); +int route_new_dynamic(Route **ret, unsigned char rtm_protocol); +void route_free(Route *route); +int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); +int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); +#define _cleanup_route_free_ _cleanup_(route_freep) + +int config_parse_gateway(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_destination(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_route_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c new file mode 100644 index 0000000000..a41cd86239 --- /dev/null +++ b/src/network/networkd-util.c @@ -0,0 +1,144 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "util.h" +#include "conf-parser.h" + +#include "networkd-util.h" + +const char *address_family_boolean_to_string(AddressFamilyBoolean b) { + if (b == ADDRESS_FAMILY_YES || + b == ADDRESS_FAMILY_NO) + return yes_no(b == ADDRESS_FAMILY_YES); + + if (b == ADDRESS_FAMILY_IPV4) + return "ipv4"; + if (b == ADDRESS_FAMILY_IPV6) + return "ipv6"; + + return NULL; +} + +AddressFamilyBoolean address_family_boolean_from_string(const char *s) { + int r; + + /* Make this a true superset of a boolean */ + + r = parse_boolean(s); + if (r > 0) + return ADDRESS_FAMILY_YES; + if (r == 0) + return ADDRESS_FAMILY_NO; + + if (streq(s, "ipv4")) + return ADDRESS_FAMILY_IPV4; + if (streq(s, "ipv6")) + return ADDRESS_FAMILY_IPV6; + + return _ADDRESS_FAMILY_BOOLEAN_INVALID; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option"); + +int config_parse_address_family_boolean_with_kernel( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + AddressFamilyBoolean *fwd = data, s; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + s = address_family_boolean_from_string(rvalue); + if (s < 0) { + if (streq(rvalue, "kernel")) + s = _ADDRESS_FAMILY_BOOLEAN_INVALID; + else { + log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding= option, ignoring: %s", rvalue); + return 0; + } + } + + *fwd = s; + + return 0; +} + +static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { + [RESOLVE_SUPPORT_NO] = "no", + [RESOLVE_SUPPORT_YES] = "yes", + [RESOLVE_SUPPORT_RESOLVE] = "resolve", +}; + +DEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport); + +int config_parse_resolve( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ResolveSupport *resolve = data; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(resolve); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + *resolve = RESOLVE_SUPPORT_YES; + else if (k == 0) + *resolve = RESOLVE_SUPPORT_NO; + else { + ResolveSupport s; + + s = resolve_support_from_string(rvalue); + if (s < 0){ + log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue); + return 0; + } + + *resolve = s; + } + + return 0; +} diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h new file mode 100644 index 0000000000..cc41aae85a --- /dev/null +++ b/src/network/networkd-util.h @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "macro.h" + +typedef enum AddressFamilyBoolean { + /* This is a bitmask, though it usually doesn't feel that way! */ + ADDRESS_FAMILY_NO = 0, + ADDRESS_FAMILY_IPV4 = 1, + ADDRESS_FAMILY_IPV6 = 2, + ADDRESS_FAMILY_YES = 3, + _ADDRESS_FAMILY_BOOLEAN_MAX, + _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, +} AddressFamilyBoolean; + +typedef enum ResolveSupport { + RESOLVE_SUPPORT_NO, + RESOLVE_SUPPORT_YES, + RESOLVE_SUPPORT_RESOLVE, + _RESOLVE_SUPPORT_MAX, + _RESOLVE_SUPPORT_INVALID = -1, +} ResolveSupport; + +int config_parse_resolve(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_address_family_boolean_with_kernel(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const char* resolve_support_to_string(ResolveSupport i) _const_; +ResolveSupport resolve_support_from_string(const char *s) _pure_; + +const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; +AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; diff --git a/src/network/networkd.h b/src/network/networkd.h index 5340922bf1..eea57ac158 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -26,213 +26,17 @@ #include "sd-event.h" #include "sd-netlink.h" #include "sd-bus.h" -#include "sd-dhcp-client.h" -#include "sd-dhcp-server.h" -#include "sd-ipv4ll.h" -#include "sd-icmp6-nd.h" -#include "sd-dhcp6-client.h" #include "udev.h" -#include "sd-lldp.h" -#include "netlink-util.h" #include "hashmap.h" #include "list.h" -#include "set.h" -#include "condition.h" -#include "in-addr-util.h" -#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU -#define DHCP_ROUTE_METRIC 1024 -#define IPV4LL_ROUTE_METRIC 2048 - -typedef struct NetDev NetDev; -typedef struct Network Network; -typedef struct Link Link; -typedef struct Address Address; -typedef struct Route Route; typedef struct Manager Manager; -typedef struct AddressPool AddressPool; -typedef struct FdbEntry FdbEntry; - -typedef enum AddressFamilyBoolean { - /* This is a bitmask, though it usually doesn't feel that way! */ - ADDRESS_FAMILY_NO = 0, - ADDRESS_FAMILY_IPV4 = 1, - ADDRESS_FAMILY_IPV6 = 2, - ADDRESS_FAMILY_YES = 3, - _ADDRESS_FAMILY_BOOLEAN_MAX, - _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, -} AddressFamilyBoolean; - -typedef enum ResolveSupport { - RESOLVE_SUPPORT_NO, - RESOLVE_SUPPORT_YES, - RESOLVE_SUPPORT_RESOLVE, - _RESOLVE_SUPPORT_MAX, - _RESOLVE_SUPPORT_INVALID = -1, -} ResolveSupport; - -typedef enum LinkOperationalState { - LINK_OPERSTATE_OFF, - LINK_OPERSTATE_NO_CARRIER, - LINK_OPERSTATE_DORMANT, - LINK_OPERSTATE_CARRIER, - LINK_OPERSTATE_DEGRADED, - LINK_OPERSTATE_ROUTABLE, - _LINK_OPERSTATE_MAX, - _LINK_OPERSTATE_INVALID = -1 -} LinkOperationalState; - -typedef enum DCHPClientIdentifier { - DHCP_CLIENT_ID_MAC, - DHCP_CLIENT_ID_DUID, - _DHCP_CLIENT_ID_MAX, - _DHCP_CLIENT_ID_INVALID = -1, -} DCHPClientIdentifier; - -typedef enum IPv6PrivacyExtensions { - /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ - IPV6_PRIVACY_EXTENSIONS_NO, - IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, - IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ - _IPV6_PRIVACY_EXTENSIONS_MAX, - _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, -} IPv6PrivacyExtensions; - -struct FdbEntry { - Network *network; - unsigned section; - - struct ether_addr *mac_addr; - uint16_t vlan_id; - - LIST_FIELDS(FdbEntry, static_fdb_entries); -}; - -struct Network { - Manager *manager; - - char *filename; - char *name; - - struct ether_addr *match_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - - Condition *match_host; - Condition *match_virt; - Condition *match_kernel; - Condition *match_arch; - - char *description; - NetDev *bridge; - NetDev *bond; - Hashmap *stacked_netdevs; - AddressFamilyBoolean dhcp; - DCHPClientIdentifier dhcp_client_identifier; - char *dhcp_vendor_class_identifier; - char *hostname; - bool dhcp_dns; - bool dhcp_ntp; - bool dhcp_mtu; - bool dhcp_hostname; - bool dhcp_domains; - bool dhcp_sendhost; - bool dhcp_broadcast; - bool dhcp_critical; - bool dhcp_routes; - unsigned dhcp_route_metric; - AddressFamilyBoolean link_local; - bool ipv4ll_route; - union in_addr_union ipv6_token; - - bool dhcp_server; - - bool use_bpdu; - bool hairpin; - bool fast_leave; - bool allow_port_to_be_root; - bool unicast_flood; - unsigned cost; - - AddressFamilyBoolean ip_forward; - bool ip_masquerade; - - IPv6PrivacyExtensions ipv6_privacy_extensions; - - struct ether_addr *mac; - unsigned mtu; - - bool lldp; - - LIST_HEAD(Address, static_addresses); - LIST_HEAD(Route, static_routes); - LIST_HEAD(FdbEntry, static_fdb_entries); - - Hashmap *addresses_by_section; - Hashmap *routes_by_section; - Hashmap *fdb_entries_by_section; - bool wildcard_domain; - char **domains, **dns, **ntp, **bind_carrier; - - ResolveSupport llmnr; - - LIST_FIELDS(Network, networks); -}; - -struct Address { - Network *network; - unsigned section; - - int family; - unsigned char prefixlen; - unsigned char scope; - uint32_t flags; - char *label; - - struct in_addr broadcast; - struct ifa_cacheinfo cinfo; - - union in_addr_union in_addr; - union in_addr_union in_addr_peer; - - bool ip_masquerade_done; - - LIST_FIELDS(Address, addresses); -}; - -struct Route { - Network *network; - unsigned section; - - int family; - unsigned char dst_prefixlen; - unsigned char src_prefixlen; - unsigned char scope; - uint32_t metrics; - unsigned char protocol; /* RTPROT_* */ - - union in_addr_union in_addr; - union in_addr_union dst_addr; - union in_addr_union src_addr; - union in_addr_union prefsrc_addr; - - LIST_FIELDS(Route, routes); -}; - -struct AddressPool { - Manager *manager; - - int family; - unsigned prefixlen; - - union in_addr_union in_addr; - - LIST_FIELDS(AddressPool, address_pools); -}; +#include "networkd-network.h" +#include "networkd-address-pool.h" +#include "networkd-link.h" +#include "networkd-util.h" struct Manager { sd_netlink *rtnl; @@ -281,183 +85,7 @@ int manager_save(Manager *m); int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found); +Link* manager_find_uplink(Manager *m, Link *exclude); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) - -/* Network */ - -int network_load(Manager *manager); - -void network_free(Network *network); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); -#define _cleanup_network_free_ _cleanup_(network_freep) - -int network_get_by_name(Manager *manager, const char *name, Network **ret); -int network_get(Manager *manager, struct udev_device *device, - const char *ifname, const struct ether_addr *mac, - Network **ret); -int network_apply(Manager *manager, Network *network, Link *link); - -int config_parse_netdev(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_domains(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -int config_parse_tunnel(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -extern const sd_bus_vtable network_vtable[]; - -int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); -int network_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); - -/* gperf */ -const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); - -/* Route */ -int route_new_static(Network *network, unsigned section, Route **ret); -int route_new_dynamic(Route **ret, unsigned char rtm_protocol); -void route_free(Route *route); -int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); -int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); - - -DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); -#define _cleanup_route_free_ _cleanup_(route_freep) - -int config_parse_gateway(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_destination(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_route_priority(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_route_scope(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); -/* Address */ -int address_new_static(Network *network, unsigned section, Address **ret); -int address_new_dynamic(Address **ret); -void address_free(Address *address); -int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_establish(Address *address, Link *link); -int address_release(Address *address, Link *link); -bool address_equal(Address *a1, Address *a2); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); -#define _cleanup_address_free_ _cleanup_(address_freep) - -int config_parse_address(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_broadcast(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_label(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* Forwarding database table. */ -int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry); -void fdb_entry_free(FdbEntry *fdb_entry); -int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret); - -DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free); -#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep) - -int config_parse_fdb_hwaddr(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_fdb_vlan_id(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* DHCP support */ - -int config_parse_dhcp(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_dhcp_client_identifier(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* IPv4LL support (legacy) */ - -int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* IPv6 support */ -int config_parse_ipv6token(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* Resolve protocols support */ - -const char* resolve_support_to_string(ResolveSupport i) _const_; -ResolveSupport resolve_support_from_string(const char *s) _pure_; - -int config_parse_resolve(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* Address Pool */ - -int address_pool_new(Manager *m, AddressPool **ret, int family, const union in_addr_union *u, unsigned prefixlen); -int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen); -void address_pool_free(AddressPool *p); - -int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found); - -const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; -AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; - -int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* IPForwarding parser */ -int config_parse_address_family_boolean_with_kernel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* Operational State */ - -const char* link_operstate_to_string(LinkOperationalState s) _const_; -LinkOperationalState link_operstate_from_string(const char *s) _pure_; - -/* IPv6 privacy extensions support */ - -const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; -IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; - -int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - - -/* Hostname */ -int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 1a2c4b28cd..3abccdb49a 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -161,8 +161,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns } if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), - basename(last)); + printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last))); if (!p1) { p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL)); @@ -185,8 +184,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags); if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), - basename(last)); + printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last))); if (!p2) { p2 = strappend(prefix, " "); diff --git a/src/shared/pager.c b/src/shared/pager.c index 13f03e798b..85f8fa5b39 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -31,18 +31,16 @@ #include "macro.h" #include "terminal-util.h" #include "signal-util.h" +#include "copy.h" static pid_t pager_pid = 0; noreturn static void pager_fallback(void) { - ssize_t n; - - do { - n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0); - } while (n > 0); + int r; - if (n < 0) { - log_error_errno(errno, "Internal pager failed: %m"); + r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (off_t) -1, false); + if (r < 0) { + log_error_errno(r, "Internal pager failed: %m"); _exit(EXIT_FAILURE); } @@ -131,6 +129,8 @@ int pager_open(bool jump_to_end) { /* Return in the parent */ if (dup2(fd[1], STDOUT_FILENO) < 0) return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); + if (dup2(fd[1], STDERR_FILENO) < 0) + return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); safe_close_pair(fd); return 1; @@ -143,6 +143,11 @@ void pager_close(void) { /* Inform pager that we are done */ fclose(stdout); + stdout = NULL; + + fclose(stderr); + stderr = NULL; + kill(pager_pid, SIGCONT); (void) wait_for_terminate(pager_pid, NULL); pager_pid = 0; diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index 5afa50a9d0..ed5bceecdd 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -34,6 +34,9 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); @@ -44,13 +47,9 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn); -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, - size_t *data_len); -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len); - -int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); -int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes); +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); #endif diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 9af3b6532d..7e4f2ffb30 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -30,11 +30,11 @@ typedef struct sd_dhcp_server sd_dhcp_server; +int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); + sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server); sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server); -int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); - int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority); int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); @@ -47,5 +47,13 @@ int sd_dhcp_server_stop(sd_dhcp_server *server); int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen); int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *start, size_t size); +int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); +int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n); +int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n); + +int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t); +int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); + int sd_dhcp_server_forcerenew(sd_dhcp_server *server); + #endif diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 4d96c867d9..4179015fbf 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -122,6 +122,9 @@ int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); /* Get the CARRIERS that are bound to current link. */ int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); +/* Get the timezone that was learnt on a specific link. */ +int sd_network_link_get_timezone(int ifindex, char **timezone); + /* Returns whether or not domains that don't match any link should be resolved * on this link. 1 for yes, 0 for no and negative value for error */ int sd_network_link_get_wildcard_domain(int ifindex); diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 36cedcd6b5..80c5852e45 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -40,7 +40,6 @@ typedef struct sd_resolve_query sd_resolve_query; /* A callback on completion */ typedef int (*sd_resolve_getaddrinfo_handler_t)(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata); typedef int (*sd_resolve_getnameinfo_handler_t)(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata); -typedef int (*sd_resolve_res_handler_t)(sd_resolve_query* q, int ret, unsigned char *answer, void *userdata); enum { SD_RESOLVE_GET_HOST = 1ULL, @@ -99,18 +98,6 @@ int sd_resolve_getaddrinfo(sd_resolve *resolve, sd_resolve_query **q, const char * if you want to query the hostname (resp. the service name). */ 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); -/* Issue a resolver query on the specified session. The arguments are - * compatible with those of libc's res_query(3). The function returns a new - * query object. When the query is completed, you may retrieve the results using - * sd_resolve_res_done(). */ -int sd_resolve_res_query(sd_resolve *resolve, sd_resolve_query **q, const char *dname, int clazz, int type, sd_resolve_res_handler_t callback, void *userdata); - -/* Issue a resolver query on the specified session. The arguments are - * compatible with those of libc's res_search(3). The function returns a new - * query object. When the query is completed, you may retrieve the results using - * sd_resolve_res_done(). */ -int sd_resolve_res_search(sd_resolve *resolve, sd_resolve_query **q, const char *dname, int clazz, int type, sd_resolve_res_handler_t callback, void *userdata); - sd_resolve_query *sd_resolve_query_ref(sd_resolve_query* q); sd_resolve_query *sd_resolve_query_unref(sd_resolve_query* q); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 21d6ee4c0c..42ae70fd1d 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -68,32 +68,15 @@ static int context_read_data(Context *c) { assert(c); - r = readlink_malloc("/etc/localtime", &t); - if (r < 0) { - if (r == -EINVAL) - log_warning("/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/."); - else - log_warning_errno(r, "Failed to get target of /etc/localtime: %m"); - } else { - const char *e; + r = get_timezone(&t); + if (r == -EINVAL) + log_warning_errno(r, "/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/."); + else if (r < 0) + log_warning_errno(r, "Failed to get target of /etc/localtime: %m"); - e = path_startswith(t, "/usr/share/zoneinfo/"); - if (!e) - e = path_startswith(t, "../usr/share/zoneinfo/"); - - if (!e) - log_warning("/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/."); - else { - c->zone = strdup(e); - if (!c->zone) - return log_oom(); - } - } - - if (isempty(c->zone)) { - free(c->zone); - c->zone = NULL; - } + free(c->zone); + c->zone = t; + t = NULL; c->local_rtc = clock_is_localtime() > 0; |