[systemd-devel] [PATCH 2/3] util.c: add copy helper functions

harald at redhat.com harald at redhat.com
Thu May 5 03:48:00 PDT 2011


From: Harald Hoyer <harald at redhat.com>

int cp_a(const char *srcpath, const char *dstpath);

copy a source directory to a destination directory recursively.

int cp_todir(const char *src, const char *target_dir);

copy a file to a directory

int install_bin(const char *src, const char *target_dir);

copy a file to a directory, with all it's libraries needed.

int copy_execute_directory(const char *src, const char *tgt);

copy a directory of files to a directory, with all libraries needed to
run the executables.
---
 src/util.c |  254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/util.h |    6 ++
 2 files changed, 260 insertions(+), 0 deletions(-)

diff --git a/src/util.c b/src/util.c
index f0051ee..27ccdf1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4666,3 +4666,257 @@ finish:
         *strv = files;
         return r;
 }
+
+static int cp_a_children(int src_fd, int dst_fd) {
+        DIR *src_d, *dst_d;
+        int ret = 0;
+
+        assert(src_fd >= 0);
+
+        /* This returns the first error we run into, but nevertheless
+         * tries to go on */
+
+        if (!(src_d = fdopendir(src_fd))) {
+                close_nointr_nofail(src_fd);
+
+                return errno == ENOENT ? 0 : -errno;
+        }
+
+        if (!(dst_d = fdopendir(dst_fd))) {
+                close_nointr_nofail(dst_fd);
+
+                return errno == ENOENT ? 0 : -errno;
+        }
+
+        for (;;) {
+                struct dirent direntbuf, *de;
+                int r;
+                struct stat st;
+
+                if ((r = readdir_r(src_d, &direntbuf, &de)) != 0) {
+                        if (ret == 0)
+                                ret = -r;
+                        break;
+                }
+
+                if (!de)
+                        break;
+
+                if (streq(de->d_name, ".") || streq(de->d_name, ".."))
+                        continue;
+
+                if (fstatat(src_fd, de->d_name, &st , 0 /*AT_SYMLINK_NOFOLLOW*/) < 0) {
+                        if (ret == 0 && errno != ENOENT)
+                                ret = -errno;
+                        continue;
+                }
+
+                if (S_ISDIR(st.st_mode)) {
+                        int subdir_src_fd;
+                        int subdir_dst_fd;
+
+                        if ((subdir_src_fd = openat(src_fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+                                if (ret == 0 && errno != ENOENT)
+                                        ret = -errno;
+                                continue;
+                        }
+
+                        mkdirat(dst_fd, de->d_name, st.st_mode);
+                        if ((subdir_dst_fd = openat(dst_fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+                                close(subdir_src_fd);
+                                if (ret == 0 && errno != ENOENT)
+                                        ret = -errno;
+                                continue;
+                        }
+
+                        if ((r = cp_a_children(subdir_src_fd, subdir_dst_fd)) < 0) {
+                                if (ret == 0)
+                                        ret = r;
+                        }
+                        close(subdir_src_fd);
+                        close(subdir_dst_fd);
+                } else if (S_ISREG(st.st_mode)) {
+                        int subdir_src_fd;
+                        int subdir_dst_fd;
+                        char buf[512];
+                        int len;
+
+                        if ((subdir_src_fd = openat(src_fd, de->d_name, O_RDONLY|O_NONBLOCK|O_CLOEXEC)) < 0) {
+                                if (ret == 0 && errno != ENOENT)
+                                        ret = -errno;
+                                continue;
+                        }
+
+                        if ((subdir_dst_fd = openat(dst_fd, de->d_name, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_CREAT, st.st_mode)) < 0) {
+                                close(subdir_src_fd);
+                                if (ret == 0 && errno != ENOENT)
+                                        ret = -errno;
+                                continue;
+                        }
+
+                        while ((len = read(subdir_src_fd, buf, 512)) > 0) {
+                                write(subdir_dst_fd, buf, len);
+                        }
+
+                        close(subdir_src_fd);
+                        close(subdir_dst_fd);
+                }
+        }
+
+        if (src_d != NULL)
+                closedir(src_d);
+        if (dst_d != NULL)
+                closedir(dst_d);
+
+        return ret;
+}
+
+int cp_a(const char *srcpath, const char *dstpath) {
+        int srcfd = -1 , dstfd = -1;
+        int r;
+
+        assert(srcpath);
+        assert(dstpath);
+
+        if ((srcfd = open(srcpath, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+
+                if (errno != ENOTDIR)
+                        return -errno;
+
+                return 0;
+        }
+
+        if ((dstfd = open(dstpath, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) {
+
+                if (errno != ENOTDIR)
+                        r = -errno;
+
+                close(srcfd);
+
+                return r;
+        }
+
+        r = cp_a_children(srcfd, dstfd);
+
+        return r;
+}
+
+int cp_todir(const char *src, const char *target_dir)
+{
+        char *tgt = NULL;
+        char buf[512];
+        int len;
+        int ret = 0;
+        int src_fd = -1, dst_fd = -1;
+        struct stat statbuf;
+
+        stat(src, &statbuf);
+        if ((statbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
+                return -ENOEXEC;
+
+        asprintf(&tgt, "%s/%s", target_dir, src);
+
+        mkdir_parents(tgt, 0755);
+
+        dst_fd = open(tgt, O_WRONLY|O_CREAT|O_EXCL, statbuf.st_mode);
+        if (dst_fd < 0) {
+                if (errno != EEXIST)
+                        perror(src);
+                ret = -1;
+                goto err;
+        }
+
+        src_fd = open(src, O_RDONLY);
+        if (src_fd < 0) {
+                perror(src);
+                ret = -1;
+                goto err;
+        }
+
+        while ((len = read(src_fd, buf, 512)) > 0) {
+                int r;
+                char *bptr = buf;
+                while (len) {
+                        r = write(dst_fd, bptr, len);
+                        if (r == -1) {
+                                ret = -1;
+                                break;
+                        }
+                        len -= r;
+                        bptr += r;
+                }
+
+        }
+ err:
+        if (src_fd >= 0)
+                close(src_fd);
+        if (dst_fd >= 0)
+                close(dst_fd);
+        return ret;
+}
+
+int install_bin(const char *src, const char *target_dir)
+{
+        char *command = NULL;
+        FILE *fp;
+        char linebuf[LINE_MAX], *pos;
+        int ret = 0;
+        ret = cp_todir(src, target_dir);
+
+        asprintf(&command, "ldd %s", src);
+        fp = popen(command, "r");
+        free(command);
+        if (fp == NULL) {
+                ret = -errno;
+                goto err;
+        }
+        while (!feof(fp)) {
+                fgets(linebuf, sizeof(linebuf)-1, fp);
+                if ((pos = strchr(linebuf, '/')) != NULL) {
+                        char *i = pos;
+                        while (*i && *i != ' ') i++;
+                        *i = 0;
+                        cp_todir(pos, target_dir);
+                }
+        }
+
+ err:
+        if (fp)
+                fclose(fp);
+        return ret;
+}
+
+
+int copy_execute_directory(const char *src, const char *tgt) {
+        DIR *_d = NULL;
+        struct dirent *de;
+        int ret = 0;
+        assert(src);
+
+        if (!(_d = opendir(src))) {
+                log_error("Failed to enumerate directory %s: %m", src);
+                return -errno;
+        }
+
+        while ((de = readdir(_d))) {
+                char *path;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if (de->d_type != DT_REG &&
+                    de->d_type != DT_LNK &&
+                    de->d_type != DT_UNKNOWN)
+                        continue;
+
+                if (asprintf(&path, "%s/%s", src, de->d_name) < 0) {
+                        log_error("Out of memory");
+                        continue;
+                }
+                ret += install_bin(path, tgt);
+        }
+
+        if (_d)
+                closedir(_d);
+        return ret;
+}
diff --git a/src/util.h b/src/util.h
index 5f6325b..b34c409 100644
--- a/src/util.h
+++ b/src/util.h
@@ -443,4 +443,10 @@ int signal_from_string(const char *s);
 int signal_from_string_try_harder(const char *s);
 
 int conf_files_list(char ***strv, const char *suffix, const char *dir, ...);
+
+int cp_a(const char *srcpath, const char *dstpath);
+int cp_todir(const char *src, const char *target_dir);
+int install_bin(const char *src, const char *target_dir);
+int copy_execute_directory(const char *src, const char *tgt);
+
 #endif
-- 
1.7.3.4



More information about the systemd-devel mailing list