[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