+static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
+{
+ int srcfd = -1;
+ int dstfd = -1;
+ int rc = -1;
+ ssize_t bread, bwritten;
+ struct stat sb;
+ char buf[10];
+ int cmp;
+ size_t to_read;
+ bool found_slash;
+
+ cmp = strcmp(src, dst);
+ if (cmp == 0) {
+ return -1;
+ }
+
+ srcfd = open(src, O_RDONLY, 0);
+ if (srcfd < 0) {
+ return -1;
+ }
+
+ if (mode == 0) {
+ rc = fstat(srcfd, &sb);
+ if (rc != 0) {
+ rc = -1;
+ goto out;
+ }
+ mode = sb.st_mode;
+ }
+
+ dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
+ if (dstfd < 0) {
+ rc = -1;
+ goto out;
+ }
+
+ found_slash = false;
+ to_read = 1;
+
+ for (;;) {
+ bread = read(srcfd, buf, to_read);
+ if (bread == 0) {
+ /* done */
+ break;
+ } else if (bread < 0) {
+ errno = EIO;
+ rc = -1;
+ goto out;
+ }
+
+ to_read = 1;
+ if (!found_slash && buf[0] == '/') {
+ found_slash = true;
+ to_read = 9;
+ }
+
+ if (found_slash && bread == 9) {
+ cmp = memcmp(buf, "etc/pam.d", 9);
+ if (cmp == 0) {
+ memcpy(buf, pdir + 1, 9);
+ }
+ found_slash = false;
+ }
+
+ bwritten = write(dstfd, buf, bread);
+ if (bwritten < 0) {
+ errno = EIO;
+ rc = -1;
+ goto out;
+ }
+
+ if (bread != bwritten) {
+ errno = EFAULT;
+ rc = -1;
+ goto out;
+ }
+ }
+
+ rc = 0;
+out:
+ if (srcfd != -1) {
+ close(srcfd);
+ }
+ if (dstfd != -1) {
+ close(dstfd);
+ }
+ if (rc < 0) {
+ unlink(dst);
+ }
+
+ return rc;
+}
+