#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
}
static ssize_t
-ps_root_dounlink(void *data, size_t len)
+ps_root_docopy(const char *dir, const char *file)
+{
+
+ char path[PATH_MAX], buf[BUFSIZ], *slash;
+ struct stat from_sb, to_sb;
+ int from_fd, to_fd;
+ ssize_t rcount, wcount, total;
+#ifdef BSD
+ struct timespec ts[2];
+#else
+ struct timeval ts[2];
+#endif
+
+ if (snprintf(path, sizeof(path), "%s/%s", dir, file) == -1)
+ return -1;
+ if (stat(file, &from_sb) == -1)
+ return -1;
+ if (stat(path, &to_sb) == 0) {
+#ifdef BSD
+ if (timespeccmp(&from_sb.st_mtimespec, &to_sb.st_mtimespec, ==))
+ return 0;
+#else
+ if (from_sb.st_mtime == to_sb.st_mtime)
+ return 0;
+#endif
+ } else {
+ /* Ensure directory exists */
+ slash = strrchr(path, '/');
+ if (slash != NULL) {
+ *slash = '\0';
+ ps_mkdir(path);
+ *slash = '/';
+ }
+ }
+
+ if (unlink(path) == -1 && errno != ENOENT)
+ return -1;
+ if ((from_fd = open(file, O_RDONLY, 0)) == -1)
+ return -1;
+ if ((to_fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0555)) == -1)
+ return -1;
+
+ total = 0;
+ while ((rcount = read(from_fd, buf, sizeof(buf))) > 0) {
+ wcount = write(to_fd, buf, (size_t)rcount);
+ if (wcount != rcount) {
+ total = -1;
+ break;
+ }
+ total += wcount;
+ }
+
+#ifdef BSD
+ ts[0] = from_sb.st_atimespec;
+ ts[1] = from_sb.st_mtimespec;
+ if (futimens(to_fd, ts) == -1)
+ total = -1;
+#else
+ tv[0].tv_sec = from_sb.st_atime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = from_sb.st_mtime;
+ tv[1].tv_usec = 0;
+ if (futimes(to_fd, ts) == -1)
+ total = -1;
+#endif
+ close(from_fd);
+ close(to_fd);
+
+ return total;
+}
+
+static ssize_t
+ps_root_docopy1(const char *file)
+{
+ struct passwd *pw;
+
+ errno = 0;
+ if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
+ if (errno == 0)
+ errno = ENOENT;
+ return -1;
+ }
+
+ return ps_root_docopy(pw->pw_dir, file);
+}
+
+static ssize_t
+ps_root_dofileop(void *data, size_t len, uint8_t op)
{
char *path = data;
size_t plen;
return -1;
}
- return (ssize_t)unlink(path);
+ switch(op) {
+ case PS_COPY:
+ return ps_root_docopy1(path);
+ case PS_UNLINK:
+ return (ssize_t)unlink(path);
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
}
static ssize_t
case PS_SCRIPT:
err = ps_root_run_script(ctx, data, len);
break;
+ case PS_COPY: /* FALLTHROUGH */
case PS_UNLINK:
- err = ps_root_dounlink(data, len);
+ err = ps_root_dofileop(data, len, psm->ps_cmd);
break;
default:
err = ps_root_os(psm, msg);
return ps_root_readerror(ctx);
}
-ssize_t
-ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path)
+static ssize_t
+ps_root_fileop(struct dhcpcd_ctx *ctx, const char *path, uint8_t op)
{
char buf[PATH_MAX], *p = buf;
size_t plen = strlen(path) + 1;
p += sizeof(plen);
memcpy(p, path, plen);
- if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_UNLINK, 0, buf, len) == -1)
+ if (ps_sendcmd(ctx, ctx->ps_root_fd, op, 0, buf, len) == -1)
return -1;
return ps_root_readerror(ctx);
}
+
+
+ssize_t
+ps_root_copychroot(struct dhcpcd_ctx *ctx, const char *path)
+{
+
+ return ps_root_fileop(ctx, path, PS_COPY);
+}
+
+ssize_t
+ps_root_unlink(struct dhcpcd_ctx *ctx, const char *path)
+{
+
+ return ps_root_fileop(ctx, path, PS_UNLINK);
+}
*/
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <util.h>
#endif
+int
+ps_mkdir(char *path)
+{
+ char *slash;
+ bool done;
+
+ slash = path;
+ for (;;) {
+ slash += strspn(slash, "/");
+ slash += strcspn(slash, "/");
+ done = (*slash == '\0');
+ *slash = '\0';
+ if (mkdir(path, 0755) == -1 && errno != EEXIST)
+ return -1;
+ if (done)
+ break;
+ *slash = '/';
+ }
+ return 0;
+}
+
int
ps_init(struct dhcpcd_ctx *ctx)
{
struct passwd *pw;
+ char path[PATH_MAX];
errno = 0;
if ((pw = getpwnam(PRIVSEP_USER)) == NULL) {
return -1;
}
+ /* Create the database directory. */
+ if (snprintf(path, sizeof(path), "%s%s", pw->pw_dir, DBDIR) == -1 ||
+ ps_mkdir(path) == -1 ||
+ chown(path, pw->pw_uid, pw->pw_gid) == -1 ||
+ chmod(path, 0755) == -1)
+ logerr("%s: %s", __func__, path);
+
ctx->options |= DHCPCD_PRIVSEP;
return 0;
}