dhcp: merge branch 'master' into th/systemd-dhcp-integration
authorThomas Haller <thaller@redhat.com>
Sun, 1 Feb 2015 14:25:19 +0000 (15:25 +0100)
committerThomas Haller <thaller@redhat.com>
Tue, 3 Mar 2015 10:13:41 +0000 (11:13 +0100)
Only basic merging. The result does not yet compile.

https://bugzilla.gnome.org/show_bug.cgi?id=742719

Conflicts:
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
src/dhcp-manager/systemd-dhcp/src/shared/macro.h
src/dhcp-manager/systemd-dhcp/src/shared/strv.c
src/dhcp-manager/systemd-dhcp/src/shared/util.c
src/dhcp-manager/systemd-dhcp/src/shared/util.h
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h

27 files changed:
1  2 
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c
src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c
src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h
src/dhcp-manager/systemd-dhcp/src/shared/list.h
src/dhcp-manager/systemd-dhcp/src/shared/macro.h
src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h
src/dhcp-manager/systemd-dhcp/src/shared/strv.c
src/dhcp-manager/systemd-dhcp/src/shared/strv.h
src/dhcp-manager/systemd-dhcp/src/shared/time-util.c
src/dhcp-manager/systemd-dhcp/src/shared/time-util.h
src/dhcp-manager/systemd-dhcp/src/shared/utf8.c
src/dhcp-manager/systemd-dhcp/src/shared/utf8.h
src/dhcp-manager/systemd-dhcp/src/shared/util.c
src/dhcp-manager/systemd-dhcp/src/shared/util.h
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h
src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h
src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h

    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
+ #include "nm-sd-adapt.h"
  #include <errno.h>
 -#include <sys/types.h>
  #include <sys/socket.h>
  #include <string.h>
  #include <linux/if_packet.h>
    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
 -#include <stdlib.h>
+ #include "nm-sd-adapt.h"
  #include <errno.h>
  #include <string.h>
 -#include <stdio.h>
  #include <net/ethernet.h>
  #include <net/if_arp.h>
 -#include <sys/param.h>
  
 -#include "util.h"
 -#include "list.h"
  
  #include "dhcp-protocol.h"
 -#include "dhcp-lease-internal.h"
  #include "dhcp-internal.h"
 -#include "sd-dhcp-lease.h"
 -#include "sd-dhcp-client.h"
  
  #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
  
  #include <netinet/ether.h>
  #include <linux/if.h>
  #include <arpa/inet.h>
 -#include <fnmatch.h>
  
+ #if 0 /* NM_IGNORED */
  #include "strv.h"
  #include "siphash24.h"
 -#include "libudev-private.h"
+ #endif /* NM_IGNORED */
  #include "dhcp-lease-internal.h"
+ #if 0 /* NM_IGNORED */
  #include "log.h"
  #include "utf8.h"
+ #endif /* NM_IGNORED */
  #include "util.h"
+ #if 0 /* NM_IGNORED */
  #include "conf-parser.h"
  #include "condition.h"
+ #endif /* NM_IGNORED */
  #include "network-internal.h"
  
+ #if 0 /* NM_IGNORED */
  const char *net_get_name(struct udev_device *device) {
          const char *name, *field;
  
    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
 -#include <netinet/ether.h>
 -#include <netinet/in.h>
+ #include "nm-sd-adapt.h"
  #include <stdbool.h>
  
+ #if 0 /* NM_IGNORED */
  #include "udev.h"
  #include "condition.h"
  
  #include <sys/ioctl.h>
  #include <linux/if_infiniband.h>
  
+ #if 0 /* NM_IGNORED */
  #include "udev.h"
  #include "udev-util.h"
 -#include "virt.h"
+ #endif /* NM_IGNORED */
 -#include "siphash24.h"
  #include "util.h"
  #include "refcnt.h"
  
@@@ -1205,7 -1175,10 +1210,9 @@@ sd_dhcp6_client *sd_dhcp6_client_unref(
  int sd_dhcp6_client_new(sd_dhcp6_client **ret)
  {
          _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
 -        sd_id128_t machine_id;
+ #if 0 /* NM_IGNORED */
          int r;
+ #endif /* NM_IGNORED */
          size_t t;
  
          assert_return(ret, -EINVAL);
  
          client->fd = -1;
  
+ #if 0 /* NM_IGNORED */
          /* initialize DUID */
 -        client->duid.en.type = htobe16(DHCP6_DUID_EN);
 -        client->duid.en.pen = htobe32(SYSTEMD_PEN);
 -        client->duid_len = sizeof(client->duid.en);
 -
 -        r = sd_id128_get_machine(&machine_id);
 +        r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
          if (r < 0)
                  return r;
 -
 -        /* a bit of snake-oil perhaps, but no need to expose the machine-id
 -           directly */
 -        siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
+ #endif /* NM_IGNORED */
  
          client->req_opts_len = ELEMENTSOF(default_req_opts);
  
@@@ -408,21 -386,7 +410,22 @@@ do 
                  _found;                                                 \
          })
  
 +/* Return a nulstr for a standard cascade of configuration directories,
 + * suitable to pass to conf_files_list_nulstr or config_parse_many. */
 +#define CONF_DIRS_NULSTR(n) \
 +        "/etc/" n ".d\0" \
 +        "/run/" n ".d\0" \
 +        "/usr/local/lib/" n ".d\0" \
 +        "/usr/lib/" n ".d\0" \
 +        CONF_DIR_SPLIT_USR(n)
 +
 +#ifdef HAVE_SPLIT_USR
 +#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
 +#else
 +#define CONF_DIR_SPLIT_USR(n)
 +#endif
 +
+ #if 0 /* NM_IGNORED */
  /* Define C11 thread_local attribute even on older gcc compiler
   * version */
  #ifndef thread_local
  #endif
  #endif
  
 +#define UID_INVALID ((uid_t) -1)
 +#define GID_INVALID ((gid_t) -1)
 +#define MODE_INVALID ((mode_t) -1)
 +
 +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)                 \
 +        static inline void func##p(type *p) {                   \
 +                if (*p)                                         \
 +                        func(*p);                               \
 +        }                                                       \
 +        struct __useless_struct_to_allow_trailing_semicolon__
 +
  #include "log.h"
+ #endif /* NM_IGNORED */
@@@ -19,6 -19,9 +19,8 @@@
    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
 -#include <assert.h>
+ #include "nm-sd-adapt.h"
  #include <stdlib.h>
  #include <stdarg.h>
  #include <string.h>
    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
+ #include "nm-sd-adapt.h"
  #include <stdarg.h>
  #include <stdbool.h>
 +#include <fnmatch.h>
  
  #include "util.h"
  
@@@ -19,6 -19,9 +19,8 @@@
    along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
  
 -#include <assert.h>
+ #include "nm-sd-adapt.h"
  #include <string.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sys/auxv.h>
  #endif
  
 +#include "config.h"
  #include "macro.h"
  #include "util.h"
+ #if 0 /* NM_IGNORED */
  #include "ioprio.h"
  #include "missing.h"
  #include "log.h"
  #include "gunicode.h"
  #include "virt.h"
  #include "def.h"
 +#include "sparse-endian.h"
+ #endif /* NM_IGNORED */
  
+ #if 0 /* NM_IGNORED */
  int saved_argc = 0;
  char **saved_argv = NULL;
  
@@@ -637,6 -565,57 +648,7 @@@ int get_parent_of_pid(pid_t pid, pid_t 
  
          return 0;
  }
 -
 -int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
 -        int r;
 -        _cleanup_free_ char *line = NULL;
 -        const char *p;
 -
 -        assert(pid >= 0);
 -        assert(st);
 -
 -        p = procfs_file_alloca(pid, "stat");
 -        r = read_one_line_file(p, &line);
 -        if (r < 0)
 -                return r;
 -
 -        /* Let's skip the pid and comm fields. The latter is enclosed
 -         * in () but does not escape any () in its value, so let's
 -         * skip over it manually */
 -
 -        p = strrchr(line, ')');
 -        if (!p)
 -                return -EIO;
 -
 -        p++;
 -
 -        if (sscanf(p, " "
 -                   "%*c "  /* state */
 -                   "%*d "  /* ppid */
 -                   "%*d "  /* pgrp */
 -                   "%*d "  /* session */
 -                   "%*d "  /* tty_nr */
 -                   "%*d "  /* tpgid */
 -                   "%*u "  /* flags */
 -                   "%*u "  /* minflt */
 -                   "%*u "  /* cminflt */
 -                   "%*u "  /* majflt */
 -                   "%*u "  /* cmajflt */
 -                   "%*u "  /* utime */
 -                   "%*u "  /* stime */
 -                   "%*d "  /* cutime */
 -                   "%*d "  /* cstime */
 -                   "%*d "  /* priority */
 -                   "%*d "  /* nice */
 -                   "%*d "  /* num_threads */
 -                   "%*d "  /* itrealvalue */
 -                   "%llu "  /* starttime */,
 -                   st) != 1)
 -                return -EIO;
 -
 -        return 0;
 -}
+ #endif /* NM_IGNORED */
  
  int fchmod_umask(int fd, mode_t m) {
          mode_t u;
@@@ -904,60 -873,8 +917,61 @@@ int get_process_gid(pid_t pid, gid_t *g
          assert_cc(sizeof(uid_t) == sizeof(gid_t));
          return get_process_id(pid, "Gid:", gid);
  }
+ #endif /* NM_IGNORED */
  
 +int get_process_cwd(pid_t pid, char **cwd) {
 +        const char *p;
 +
 +        assert(pid >= 0);
 +
 +        p = procfs_file_alloca(pid, "cwd");
 +
 +        return get_process_link_contents(p, cwd);
 +}
 +
 +int get_process_root(pid_t pid, char **root) {
 +        const char *p;
 +
 +        assert(pid >= 0);
 +
 +        p = procfs_file_alloca(pid, "root");
 +
 +        return get_process_link_contents(p, root);
 +}
 +
 +int get_process_environ(pid_t pid, char **env) {
 +        _cleanup_fclose_ FILE *f = NULL;
 +        _cleanup_free_ char *outcome = NULL;
 +        int c;
 +        const char *p;
 +        size_t allocated = 0, sz = 0;
 +
 +        assert(pid >= 0);
 +        assert(env);
 +
 +        p = procfs_file_alloca(pid, "environ");
 +
 +        f = fopen(p, "re");
 +        if (!f)
 +                return -errno;
 +
 +        while ((c = fgetc(f)) != EOF) {
 +                if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
 +                        return -ENOMEM;
 +
 +                if (c == '\0')
 +                        outcome[sz++] = '\n';
 +                else
 +                        sz += cescape_char(c, outcome + sz);
 +        }
 +
 +        outcome[sz] = '\0';
 +        *env = outcome;
 +        outcome = NULL;
 +
 +        return 0;
 +}
 +
  char *strnappend(const char *s, const char *suffix, size_t b) {
          size_t a;
          char *r;
@@@ -1687,9 -1657,9 +1707,10 @@@ bool chars_intersect(const char *a, con
          return false;
  }
  
+ #if 0 /* NM_IGNORED */
  bool fstype_is_network(const char *fstype) {
          static const char table[] =
 +                "afs\0"
                  "cifs\0"
                  "smbfs\0"
                  "sshfs\0"
@@@ -2326,8 -2304,10 +2348,9 @@@ ssize_t loop_read(int fd, void *buf, si
          return n;
  }
  
 -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
+ #if 0 /* NM_IGNORED */
 +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
          const uint8_t *p = buf;
 -        ssize_t n = 0;
  
          assert(fd >= 0);
          assert(buf);
@@@ -7090,36 -6955,27 +7135,37 @@@ int fflush_and_check(FILE *f) 
          return 0;
  }
  
 -char *tempfn_xxxxxx(const char *p) {
 +int tempfn_xxxxxx(const char *p, char **ret) {
          const char *fn;
          char *t;
 -        size_t k;
  
          assert(p);
 +        assert(ret);
  
 -        t = new(char, strlen(p) + 1 + 6 + 1);
 -        if (!t)
 -                return NULL;
 +        /*
 +         * Turns this:
 +         *         /foo/bar/waldo
 +         *
 +         * Into this:
 +         *         /foo/bar/.#waldoXXXXXX
 +         */
  
          fn = basename(p);
 -        k = fn - p;
 +        if (!filename_is_valid(fn))
 +                return -EINVAL;
 +
 +        t = new(char, strlen(p) + 2 + 6 + 1);
 +        if (!t)
 +                return -ENOMEM;
  
 -        strcpy(stpcpy(stpcpy(mempcpy(t, p, k), "."), fn), "XXXXXX");
 +        strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX");
  
 -        return t;
 +        *ret = path_kill_slashes(t);
 +        return 0;
  }
  
 -char *tempfn_random(const char *p) {
+ #if 0 /* NM_IGNORED */
 +int tempfn_random(const char *p, char **ret) {
          const char *fn;
          char *t, *x;
          uint64_t u;
  
          *x = 0;
  
 -        return t;
 +        *ret = path_kill_slashes(t);
 +        return 0;
 +}
 +
 +int tempfn_random_child(const char *p, char **ret) {
 +        char *t, *x;
 +        uint64_t u;
 +        unsigned i;
 +
 +        assert(p);
 +        assert(ret);
 +
 +        /* Turns this:
 +         *         /foo/bar/waldo
 +         * Into this:
 +         *         /foo/bar/waldo/.#3c2b6219aa75d7d0
 +         */
 +
 +        t = new(char, strlen(p) + 3 + 16 + 1);
 +        if (!t)
 +                return -ENOMEM;
 +
 +        x = stpcpy(stpcpy(t, p), "/.#");
 +
 +        u = random_u64();
 +        for (i = 0; i < 16; i++) {
 +                *(x++) = hexchar(u & 0xF);
 +                u >>= 4;
 +        }
 +
 +        *x = 0;
 +
 +        *ret = path_kill_slashes(t);
 +        return 0;
  }
+ #endif /* NM_IGNORED */
  
  /* make sure the hostname is not "localhost" */
  bool is_localhost(const char *hostname) {
@@@ -7526,595 -7342,5 +7574,596 @@@ int sethostname_idempotent(const char *
  
          return 1;
  }
 -#endif /* NM_IGNORED */
  
 +int ptsname_malloc(int fd, char **ret) {
 +        size_t l = 100;
 +
 +        assert(fd >= 0);
 +        assert(ret);
 +
 +        for (;;) {
 +                char *c;
 +
 +                c = new(char, l);
 +                if (!c)
 +                        return -ENOMEM;
 +
 +                if (ptsname_r(fd, c, l) == 0) {
 +                        *ret = c;
 +                        return 0;
 +                }
 +                if (errno != ERANGE) {
 +                        free(c);
 +                        return -errno;
 +                }
 +
 +                free(c);
 +                l *= 2;
 +        }
 +}
 +
 +int openpt_in_namespace(pid_t pid, int flags) {
 +        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
 +        _cleanup_close_pair_ int pair[2] = { -1, -1 };
 +        union {
 +                struct cmsghdr cmsghdr;
 +                uint8_t buf[CMSG_SPACE(sizeof(int))];
 +        } control = {};
 +        struct msghdr mh = {
 +                .msg_control = &control,
 +                .msg_controllen = sizeof(control),
 +        };
 +        struct cmsghdr *cmsg;
 +        siginfo_t si;
 +        pid_t child;
 +        int r;
 +
 +        assert(pid > 0);
 +
 +        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
 +        if (r < 0)
 +                return r;
 +
 +        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
 +                return -errno;
 +
 +        child = fork();
 +        if (child < 0)
 +                return -errno;
 +
 +        if (child == 0) {
 +                int master;
 +
 +                pair[0] = safe_close(pair[0]);
 +
 +                r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
 +                if (r < 0)
 +                        _exit(EXIT_FAILURE);
 +
 +                master = posix_openpt(flags);
 +                if (master < 0)
 +                        _exit(EXIT_FAILURE);
 +
 +                cmsg = CMSG_FIRSTHDR(&mh);
 +                cmsg->cmsg_level = SOL_SOCKET;
 +                cmsg->cmsg_type = SCM_RIGHTS;
 +                cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 +                memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
 +
 +                mh.msg_controllen = cmsg->cmsg_len;
 +
 +                if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
 +                        _exit(EXIT_FAILURE);
 +
 +                _exit(EXIT_SUCCESS);
 +        }
 +
 +        pair[1] = safe_close(pair[1]);
 +
 +        r = wait_for_terminate(child, &si);
 +        if (r < 0)
 +                return r;
 +        if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
 +                return -EIO;
 +
 +        if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
 +                return -errno;
 +
 +        for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
 +                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
 +                        int *fds;
 +                        unsigned n_fds;
 +
 +                        fds = (int*) CMSG_DATA(cmsg);
 +                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
 +
 +                        if (n_fds != 1) {
 +                                close_many(fds, n_fds);
 +                                return -EIO;
 +                        }
 +
 +                        return fds[0];
 +                }
 +
 +        return -EIO;
 +}
 +
 +ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
 +        _cleanup_close_ int fd = -1;
 +        ssize_t l;
 +
 +        /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
 +
 +        fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
 +        if (fd < 0)
 +                return -errno;
 +
 +        l = fgetxattr(fd, attribute, value, size);
 +        if (l < 0)
 +                return -errno;
 +
 +        return l;
 +}
 +
 +static int parse_crtime(le64_t le, usec_t *usec) {
 +        uint64_t u;
 +
 +        assert(usec);
 +
 +        u = le64toh(le);
 +        if (u == 0 || u == (uint64_t) -1)
 +                return -EIO;
 +
 +        *usec = (usec_t) u;
 +        return 0;
 +}
 +
 +int fd_getcrtime(int fd, usec_t *usec) {
 +        le64_t le;
 +        ssize_t n;
 +
 +        assert(fd >= 0);
 +        assert(usec);
 +
 +        /* Until Linux gets a real concept of birthtime/creation time,
 +         * let's fake one with xattrs */
 +
 +        n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
 +        if (n < 0)
 +                return -errno;
 +        if (n != sizeof(le))
 +                return -EIO;
 +
 +        return parse_crtime(le, usec);
 +}
 +
 +int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
 +        le64_t le;
 +        ssize_t n;
 +
 +        n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
 +        if (n < 0)
 +                return -errno;
 +        if (n != sizeof(le))
 +                return -EIO;
 +
 +        return parse_crtime(le, usec);
 +}
 +
 +int path_getcrtime(const char *p, usec_t *usec) {
 +        le64_t le;
 +        ssize_t n;
 +
 +        assert(p);
 +        assert(usec);
 +
 +        n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
 +        if (n < 0)
 +                return -errno;
 +        if (n != sizeof(le))
 +                return -EIO;
 +
 +        return parse_crtime(le, usec);
 +}
 +
 +int fd_setcrtime(int fd, usec_t usec) {
 +        le64_t le;
 +
 +        assert(fd >= 0);
 +
 +        if (usec <= 0)
 +                usec = now(CLOCK_REALTIME);
 +
 +        le = htole64((uint64_t) usec);
 +        if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
 +                return -errno;
 +
 +        return 0;
 +}
 +
 +int same_fd(int a, int b) {
 +        struct stat sta, stb;
 +        pid_t pid;
 +        int r, fa, fb;
 +
 +        assert(a >= 0);
 +        assert(b >= 0);
 +
 +        /* Compares two file descriptors. Note that semantics are
 +         * quite different depending on whether we have kcmp() or we
 +         * don't. If we have kcmp() this will only return true for
 +         * dup()ed file descriptors, but not otherwise. If we don't
 +         * have kcmp() this will also return true for two fds of the same
 +         * file, created by separate open() calls. Since we use this
 +         * call mostly for filtering out duplicates in the fd store
 +         * this difference hopefully doesn't matter too much. */
 +
 +        if (a == b)
 +                return true;
 +
 +        /* Try to use kcmp() if we have it. */
 +        pid = getpid();
 +        r = kcmp(pid, pid, KCMP_FILE, a, b);
 +        if (r == 0)
 +                return true;
 +        if (r > 0)
 +                return false;
 +        if (errno != ENOSYS)
 +                return -errno;
 +
 +        /* We don't have kcmp(), use fstat() instead. */
 +        if (fstat(a, &sta) < 0)
 +                return -errno;
 +
 +        if (fstat(b, &stb) < 0)
 +                return -errno;
 +
 +        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
 +                return false;
 +
 +        /* We consider all device fds different, since two device fds
 +         * might refer to quite different device contexts even though
 +         * they share the same inode and backing dev_t. */
 +
 +        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
 +                return false;
 +
 +        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
 +                return false;
 +
 +        /* The fds refer to the same inode on disk, let's also check
 +         * if they have the same fd flags. This is useful to
 +         * distuingish the read and write side of a pipe created with
 +         * pipe(). */
 +        fa = fcntl(a, F_GETFL);
 +        if (fa < 0)
 +                return -errno;
 +
 +        fb = fcntl(b, F_GETFL);
 +        if (fb < 0)
 +                return -errno;
 +
 +        return fa == fb;
 +}
 +
 +int chattr_fd(int fd, bool b, unsigned mask) {
 +        unsigned old_attr, new_attr;
 +
 +        assert(fd >= 0);
 +
 +        if (mask == 0)
 +                return 0;
 +
 +        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
 +                return -errno;
 +
 +        if (b)
 +                new_attr = old_attr | mask;
 +        else
 +                new_attr = old_attr & ~mask;
 +
 +        if (new_attr == old_attr)
 +                return 0;
 +
 +        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
 +                return -errno;
 +
 +        return 0;
 +}
 +
 +int chattr_path(const char *p, bool b, unsigned mask) {
 +        _cleanup_close_ int fd = -1;
 +
 +        assert(p);
 +
 +        if (mask == 0)
 +                return 0;
 +
 +        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
 +        if (fd < 0)
 +                return -errno;
 +
 +        return chattr_fd(fd, b, mask);
 +}
 +
 +int read_attr_fd(int fd, unsigned *ret) {
 +        assert(fd >= 0);
 +
 +        if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
 +                return -errno;
 +
 +        return 0;
 +}
 +
 +int read_attr_path(const char *p, unsigned *ret) {
 +        _cleanup_close_ int fd = -1;
 +
 +        assert(p);
 +        assert(ret);
 +
 +        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
 +        if (fd < 0)
 +                return -errno;
 +
 +        return read_attr_fd(fd, ret);
 +}
 +
 +int make_lock_file(const char *p, int operation, LockFile *ret) {
 +        _cleanup_close_ int fd = -1;
 +        _cleanup_free_ char *t = NULL;
 +        int r;
 +
 +        /*
 +         * We use UNPOSIX locks if they are available. They have nice
 +         * semantics, and are mostly compatible with NFS. However,
 +         * they are only available on new kernels. When we detect we
 +         * are running on an older kernel, then we fall back to good
 +         * old BSD locks. They also have nice semantics, but are
 +         * slightly problematic on NFS, where they are upgraded to
 +         * POSIX locks, even though locally they are orthogonal to
 +         * POSIX locks.
 +         */
 +
 +        t = strdup(p);
 +        if (!t)
 +                return -ENOMEM;
 +
 +        for (;;) {
 +                struct flock fl = {
 +                        .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
 +                        .l_whence = SEEK_SET,
 +                };
 +                struct stat st;
 +
 +                fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
 +                if (fd < 0)
 +                        return -errno;
 +
 +                r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
 +                if (r < 0) {
 +
 +                        /* If the kernel is too old, use good old BSD locks */
 +                        if (errno == EINVAL)
 +                                r = flock(fd, operation);
 +
 +                        if (r < 0)
 +                                return errno == EAGAIN ? -EBUSY : -errno;
 +                }
 +
 +                /* If we acquired the lock, let's check if the file
 +                 * still exists in the file system. If not, then the
 +                 * previous exclusive owner removed it and then closed
 +                 * it. In such a case our acquired lock is worthless,
 +                 * hence try again. */
 +
 +                r = fstat(fd, &st);
 +                if (r < 0)
 +                        return -errno;
 +                if (st.st_nlink > 0)
 +                        break;
 +
 +                fd = safe_close(fd);
 +        }
 +
 +        ret->path = t;
 +        ret->fd = fd;
 +        ret->operation = operation;
 +
 +        fd = -1;
 +        t = NULL;
 +
 +        return r;
 +}
 +
 +int make_lock_file_for(const char *p, int operation, LockFile *ret) {
 +        const char *fn;
 +        char *t;
 +
 +        assert(p);
 +        assert(ret);
 +
 +        fn = basename(p);
 +        if (!filename_is_valid(fn))
 +                return -EINVAL;
 +
 +        t = newa(char, strlen(p) + 2 + 4 + 1);
 +        stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
 +
 +        return make_lock_file(t, operation, ret);
 +}
 +
 +void release_lock_file(LockFile *f) {
 +        int r;
 +
 +        if (!f)
 +                return;
 +
 +        if (f->path) {
 +
 +                /* If we are the exclusive owner we can safely delete
 +                 * the lock file itself. If we are not the exclusive
 +                 * owner, we can try becoming it. */
 +
 +                if (f->fd >= 0 &&
 +                    (f->operation & ~LOCK_NB) == LOCK_SH) {
 +                        static const struct flock fl = {
 +                                .l_type = F_WRLCK,
 +                                .l_whence = SEEK_SET,
 +                        };
 +
 +                        r = fcntl(f->fd, F_OFD_SETLK, &fl);
 +                        if (r < 0 && errno == EINVAL)
 +                                r = flock(f->fd, LOCK_EX|LOCK_NB);
 +
 +                        if (r >= 0)
 +                                f->operation = LOCK_EX|LOCK_NB;
 +                }
 +
 +                if ((f->operation & ~LOCK_NB) == LOCK_EX)
 +                        unlink_noerrno(f->path);
 +
 +                free(f->path);
 +                f->path = NULL;
 +        }
 +
 +        f->fd = safe_close(f->fd);
 +        f->operation = 0;
 +}
 +
 +static size_t nul_length(const uint8_t *p, size_t sz) {
 +        size_t n = 0;
 +
 +        while (sz > 0) {
 +                if (*p != 0)
 +                        break;
 +
 +                n++;
 +                p++;
 +                sz--;
 +        }
 +
 +        return n;
 +}
 +
 +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
 +        const uint8_t *q, *w, *e;
 +        ssize_t l;
 +
 +        q = w = p;
 +        e = q + sz;
 +        while (q < e) {
 +                size_t n;
 +
 +                n = nul_length(q, e - q);
 +
 +                /* If there are more than the specified run length of
 +                 * NUL bytes, or if this is the beginning or the end
 +                 * of the buffer, then seek instead of write */
 +                if ((n > run_length) ||
 +                    (n > 0 && q == p) ||
 +                    (n > 0 && q + n >= e)) {
 +                        if (q > w) {
 +                                l = write(fd, w, q - w);
 +                                if (l < 0)
 +                                        return -errno;
 +                                if (l != q -w)
 +                                        return -EIO;
 +                        }
 +
 +                        if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
 +                                return -errno;
 +
 +                        q += n;
 +                        w = q;
 +                } else if (n > 0)
 +                        q += n;
 +                else
 +                        q ++;
 +        }
 +
 +        if (q > w) {
 +                l = write(fd, w, q - w);
 +                if (l < 0)
 +                        return -errno;
 +                if (l != q - w)
 +                        return -EIO;
 +        }
 +
 +        return q - (const uint8_t*) p;
 +}
 +
 +void sigkill_wait(pid_t *pid) {
 +        if (!pid)
 +                return;
 +        if (*pid <= 1)
 +                return;
 +
 +        if (kill(*pid, SIGKILL) > 0)
 +                (void) wait_for_terminate(*pid, NULL);
 +}
 +
 +int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
 +        int a = 0, b = 0, c = 0;
 +        int k;
 +
 +        assert(p);
 +        assert(*p);
 +        assert(priority);
 +
 +        if ((*p)[0] != '<')
 +                return 0;
 +
 +        if (!strchr(*p, '>'))
 +                return 0;
 +
 +        if ((*p)[2] == '>') {
 +                c = undecchar((*p)[1]);
 +                k = 3;
 +        } else if ((*p)[3] == '>') {
 +                b = undecchar((*p)[1]);
 +                c = undecchar((*p)[2]);
 +                k = 4;
 +        } else if ((*p)[4] == '>') {
 +                a = undecchar((*p)[1]);
 +                b = undecchar((*p)[2]);
 +                c = undecchar((*p)[3]);
 +                k = 5;
 +        } else
 +                return 0;
 +
 +        if (a < 0 || b < 0 || c < 0 ||
 +            (!with_facility && (a || b || c > 7)))
 +                return 0;
 +
 +        if (with_facility)
 +                *priority = a*100 + b*10 + c;
 +        else
 +                *priority = (*priority & LOG_FACMASK) | c;
 +
 +        *p += k;
 +        return 1;
 +}
 +
 +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
 +        size_t i;
 +
 +        if (!key)
 +                return -1;
 +
 +        for (i = 0; i < len; ++i)
 +                if (streq_ptr(table[i], key))
 +                        return (ssize_t)i;
 +
 +        return -1;
 +}
 +
 +void cmsg_close_all(struct msghdr *mh) {
 +        struct cmsghdr *cmsg;
 +
 +        assert(mh);
 +
 +        for (cmsg = CMSG_FIRSTHDR(mh); cmsg; cmsg = CMSG_NXTHDR(mh, cmsg))
 +                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
 +                        close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
 +}
++#endif /* NM_IGNORED */
  #include <unistd.h>
  #include <locale.h>
  #include <mntent.h>
 -#include <sys/socket.h>
 +#include <sys/inotify.h>
  
+ #if 0 /* NM_IGNORED */
  #if SIZEOF_PID_T == 4
 -#  define PID_FMT "%" PRIu32
 +#  define PID_PRI PRIi32
  #elif SIZEOF_PID_T == 2
 -#  define PID_FMT "%" PRIu16
 +#  define PID_PRI PRIi16
  #else
  #  error Unknown pid_t size
  #endif
@@@ -989,13 -1001,16 +997,15 @@@ const char *personality_to_string(unsig
  
  uint64_t physical_memory(void);
  
 -char* mount_test_option(const char *haystack, const char *needle);
 -
  void hexdump(FILE *f, const void *p, size_t s);
  
+ #if 0 /* NM_IGNORED */
  union file_handle_union {
          struct file_handle handle;
          char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
  };
 +#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
+ #endif /* NM_IGNORED */
  
  int update_reboot_param_file(const char *param);
  
@@@ -48,10 -49,7 +50,11 @@@ int sd_dhcp6_client_set_mac(sd_dhcp6_cl
                              size_t addr_len, uint16_t arp_type);
  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_information_request(sd_dhcp6_client *client,
 +                                            bool enabled);
 +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
 +                                            bool *enabled);
+ int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname);
  int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
                                         uint16_t option);