Compare commits

...

12 Commits

Author SHA1 Message Date
Marek Marczykowski-Górecki 787f3f1502
version 3.1.10
8 years ago
Marek Marczykowski-Górecki a4f0ddecb7
udev-block-add-change: fix checking if partition is mounted
8 years ago
Rusty Bird addc1d9776
udev-block-add-change: simplify a check
8 years ago
Rusty Bird 1777a1e589
udev-block-add-change: don't exclude already attached devs
8 years ago
Rusty Bird 580272ed41
udev-block-add-change: better mount status check
8 years ago
Marek Marczykowski-Górecki c6eb739151
debian: add pkg-config to Build-Depends
8 years ago
Marek Marczykowski-Górecki 80a1c7d3d0
debian: reformat Build-Depends
8 years ago
Marek Marczykowski-Górecki 0ff9e5a785
version 3.1.9
8 years ago
Marek Marczykowski-Górecki 774803003e
qrexec-lib: convert tabs to spaces
8 years ago
Marek Marczykowski-Górecki a465359a5d
udev: fix deadlock on xenstore access during dom0 boot
8 years ago
Marek Marczykowski-Górecki 95eeeef86c
udev/qvm-block: exclude device if its partition is already attached
8 years ago
Marek Marczykowski-Górecki 4fee631c94
udev/qvm-block: exclude devices used elsewhere
8 years ago

25
debian/changelog vendored

@ -1,3 +1,28 @@
qubes-utils (3.1.10) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ]
* debian: reformat Build-Depends
* debian: add pkg-config to Build-Depends
[ Rusty Bird ]
* udev-block-add-change: better mount status check
* udev-block-add-change: don't exclude already attached devs
* udev-block-add-change: simplify a check
[ Marek Marczykowski-Górecki ]
* udev-block-add-change: fix checking if partition is mounted
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 20 Nov 2016 17:05:41 +0100
qubes-utils (3.1.9) wheezy; urgency=medium
* udev/qvm-block: exclude devices used elsewhere
* udev/qvm-block: exclude device if its partition is already attached
* udev: fix deadlock on xenstore access during dom0 boot
* qrexec-lib: convert tabs to spaces
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 25 Jun 2016 15:35:35 +0200
qubes-utils (3.1.8) wheezy; urgency=medium qubes-utils (3.1.8) wheezy; urgency=medium
[ Marek Marczykowski-Górecki ] [ Marek Marczykowski-Górecki ]

8
debian/control vendored

@ -2,7 +2,13 @@ Source: qubes-utils
Section: admin Section: admin
Priority: extra Priority: extra
Maintainer: Davíð Steinn Geirsson <david@dsg.is> Maintainer: Davíð Steinn Geirsson <david@dsg.is>
Build-Depends: libvchan-xen-dev, libxen-dev, debhelper (>= 9.0.0), dh-systemd, dkms Build-Depends:
libvchan-xen-dev,
libxen-dev,
pkg-config,
debhelper (>= 9.0.0),
dh-systemd,
dkms
Standards-Version: 3.9.3 Standards-Version: 3.9.3
Homepage: http://www.qubes-os.org Homepage: http://www.qubes-os.org
Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git

@ -28,88 +28,88 @@
static int total_mem; static int total_mem;
static char *limited_malloc(int len) static char *limited_malloc(int len)
{ {
char *ret; char *ret;
total_mem += len; total_mem += len;
if (total_mem > BUFFER_LIMIT) { if (total_mem > BUFFER_LIMIT) {
fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n"); fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n");
exit(1); exit(1);
} }
ret = malloc(len); ret = malloc(len);
if (!ret) { if (!ret) {
perror("malloc"); perror("malloc");
exit(1); exit(1);
} }
return ret; return ret;
} }
static void limited_free(char *ptr, int len) static void limited_free(char *ptr, int len)
{ {
free(ptr); free(ptr);
total_mem -= len; total_mem -= len;
} }
void buffer_init(struct buffer *b) void buffer_init(struct buffer *b)
{ {
b->buflen = 0; b->buflen = 0;
b->data = NULL; b->data = NULL;
} }
void buffer_free(struct buffer *b) void buffer_free(struct buffer *b)
{ {
if (b->buflen) if (b->buflen)
limited_free(b->data, b->buflen); limited_free(b->data, b->buflen);
buffer_init(b); buffer_init(b);
} }
/* /*
The following two functions can be made much more efficient. The following two functions can be made much more efficient.
Yet the profiling output show they are not significant CPU hogs, so Yet the profiling output show they are not significant CPU hogs, so
we keep them so simple to make them obviously correct. we keep them so simple to make them obviously correct.
*/ */
void buffer_append(struct buffer *b, const char *data, int len) void buffer_append(struct buffer *b, const char *data, int len)
{ {
int newsize; int newsize;
char *qdata; char *qdata;
if (len < 0 || len > BUFFER_LIMIT) { if (len < 0 || len > BUFFER_LIMIT) {
fprintf(stderr, "buffer_append %d\n", len); fprintf(stderr, "buffer_append %d\n", len);
exit(1); exit(1);
} }
if (len == 0) if (len == 0)
return; return;
newsize = len + b->buflen; newsize = len + b->buflen;
qdata = limited_malloc(len + b->buflen); qdata = limited_malloc(len + b->buflen);
memcpy(qdata, b->data, b->buflen); memcpy(qdata, b->data, b->buflen);
memcpy(qdata + b->buflen, data, len); memcpy(qdata + b->buflen, data, len);
buffer_free(b); buffer_free(b);
b->buflen = newsize; b->buflen = newsize;
b->data = qdata; b->data = qdata;
} }
void buffer_remove(struct buffer *b, int len) void buffer_remove(struct buffer *b, int len)
{ {
int newsize; int newsize;
char *qdata = NULL; char *qdata = NULL;
if (len < 0 || len > b->buflen) { if (len < 0 || len > b->buflen) {
fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen); fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen);
exit(1); exit(1);
} }
newsize = b->buflen - len; newsize = b->buflen - len;
if (newsize > 0) { if (newsize > 0) {
qdata = limited_malloc(newsize); qdata = limited_malloc(newsize);
memcpy(qdata, b->data + len, newsize); memcpy(qdata, b->data + len, newsize);
} }
buffer_free(b); buffer_free(b);
b->buflen = newsize; b->buflen = newsize;
b->data = qdata; b->data = qdata;
} }
int buffer_len(struct buffer *b) int buffer_len(struct buffer *b)
{ {
return b->buflen; return b->buflen;
} }
void *buffer_data(struct buffer *b) void *buffer_data(struct buffer *b)
{ {
return b->data; return b->data;
} }

@ -6,44 +6,44 @@
notify_progress_t *notify_progress_func = NULL; notify_progress_t *notify_progress_func = NULL;
void register_notify_progress(notify_progress_t *func) void register_notify_progress(notify_progress_t *func)
{ {
notify_progress_func = func; notify_progress_func = func;
} }
int copy_file(int outfd, int infd, long long size, unsigned long *crc32) int copy_file(int outfd, int infd, long long size, unsigned long *crc32)
{ {
char buf[4096]; char buf[4096];
long long written = 0; long long written = 0;
int ret; int ret;
int count; int count;
while (written < size) { while (written < size) {
if (size - written > (int)sizeof(buf)) if (size - written > (int)sizeof(buf))
count = sizeof buf; count = sizeof buf;
else else
count = size - written; count = size - written;
ret = read(infd, buf, count); ret = read(infd, buf, count);
if (!ret) if (!ret)
return COPY_FILE_READ_EOF; return COPY_FILE_READ_EOF;
if (ret < 0) if (ret < 0)
return COPY_FILE_READ_ERROR; return COPY_FILE_READ_ERROR;
/* acumulate crc32 if requested */ /* acumulate crc32 if requested */
if (crc32) if (crc32)
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret); *crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
if (!write_all(outfd, buf, ret)) if (!write_all(outfd, buf, ret))
return COPY_FILE_WRITE_ERROR; return COPY_FILE_WRITE_ERROR;
if (notify_progress_func != NULL) if (notify_progress_func != NULL)
notify_progress_func(ret, 0); notify_progress_func(ret, 0);
written += ret; written += ret;
} }
return COPY_FILE_OK; return COPY_FILE_OK;
} }
const char * copy_file_status_to_str(int status) const char * copy_file_status_to_str(int status)
{ {
switch (status) { switch (status) {
case COPY_FILE_OK: return "OK"; case COPY_FILE_OK: return "OK";
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading"; case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
case COPY_FILE_READ_ERROR: return "Error reading"; case COPY_FILE_READ_ERROR: return "Error reading";
case COPY_FILE_WRITE_ERROR: return "Error writing"; case COPY_FILE_WRITE_ERROR: return "Error writing";
default: return "????????"; default: return "????????";
} }
} }

@ -28,56 +28,56 @@
static do_exec_t *exec_func = NULL; static do_exec_t *exec_func = NULL;
void register_exec_func(do_exec_t *func) { void register_exec_func(do_exec_t *func) {
exec_func = func; exec_func = func;
} }
void fix_fds(int fdin, int fdout, int fderr) void fix_fds(int fdin, int fdout, int fderr)
{ {
int i; int i;
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (i != fdin && i != fdout && i != fderr) if (i != fdin && i != fdout && i != fderr)
close(i); close(i);
dup2(fdin, 0); dup2(fdin, 0);
dup2(fdout, 1); dup2(fdout, 1);
dup2(fderr, 2); dup2(fderr, 2);
close(fdin); close(fdin);
close(fdout); close(fdout);
if (fderr != 2) if (fderr != 2)
close(fderr); close(fderr);
} }
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd, void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
int *stderr_fd) int *stderr_fd)
{ {
int inpipe[2], outpipe[2], errpipe[2]; int inpipe[2], outpipe[2], errpipe[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) || if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) ||
socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe) || socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe) ||
(stderr_fd && socketpair(AF_UNIX, SOCK_STREAM, 0, errpipe))) { (stderr_fd && socketpair(AF_UNIX, SOCK_STREAM, 0, errpipe))) {
perror("socketpair"); perror("socketpair");
exit(1); exit(1);
} }
switch (*pid = fork()) { switch (*pid = fork()) {
case -1: case -1:
perror("fork"); perror("fork");
exit(-1); exit(-1);
case 0: case 0:
if (stderr_fd) { if (stderr_fd) {
fix_fds(inpipe[0], outpipe[1], errpipe[1]); fix_fds(inpipe[0], outpipe[1], errpipe[1]);
} else } else
fix_fds(inpipe[0], outpipe[1], 2); fix_fds(inpipe[0], outpipe[1], 2);
if (exec_func != NULL) if (exec_func != NULL)
exec_func(cmdline); exec_func(cmdline);
exit(-1); exit(-1);
default:; default:;
} }
close(inpipe[0]); close(inpipe[0]);
close(outpipe[1]); close(outpipe[1]);
*stdin_fd = inpipe[1]; *stdin_fd = inpipe[1];
*stdout_fd = outpipe[0]; *stdout_fd = outpipe[0];
if (stderr_fd) { if (stderr_fd) {
close(errpipe[1]); close(errpipe[1]);
*stderr_fd = errpipe[0]; *stderr_fd = errpipe[0];
} }
} }

@ -27,90 +27,90 @@
void perror_wrapper(const char * msg) void perror_wrapper(const char * msg)
{ {
int prev=errno; int prev=errno;
perror(msg); perror(msg);
errno=prev; errno=prev;
} }
void set_nonblock(int fd) void set_nonblock(int fd)
{ {
int fl = fcntl(fd, F_GETFL, 0); int fl = fcntl(fd, F_GETFL, 0);
if (fl & O_NONBLOCK) if (fl & O_NONBLOCK)
return; return;
fcntl(fd, F_SETFL, fl | O_NONBLOCK); fcntl(fd, F_SETFL, fl | O_NONBLOCK);
} }
void set_block(int fd) void set_block(int fd)
{ {
int fl = fcntl(fd, F_GETFL, 0); int fl = fcntl(fd, F_GETFL, 0);
if (!(fl & O_NONBLOCK)) if (!(fl & O_NONBLOCK))
return; return;
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK); fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
} }
int write_all(int fd, const void *buf, int size) int write_all(int fd, const void *buf, int size)
{ {
int written = 0; int written = 0;
int ret; int ret;
while (written < size) { while (written < size) {
ret = write(fd, (char *) buf + written, size - written); ret = write(fd, (char *) buf + written, size - written);
if (ret == -1 && errno == EINTR) if (ret == -1 && errno == EINTR)
continue; continue;
if (ret <= 0) { if (ret <= 0) {
return 0; return 0;
} }
written += ret; written += ret;
} }
// fprintf(stderr, "sent %d bytes\n", size); // fprintf(stderr, "sent %d bytes\n", size);
return 1; return 1;
} }
int read_all(int fd, void *buf, int size) int read_all(int fd, void *buf, int size)
{ {
int got_read = 0; int got_read = 0;
int ret; int ret;
while (got_read < size) { while (got_read < size) {
ret = read(fd, (char *) buf + got_read, size - got_read); ret = read(fd, (char *) buf + got_read, size - got_read);
if (ret == -1 && errno == EINTR) if (ret == -1 && errno == EINTR)
continue; continue;
if (ret == 0) { if (ret == 0) {
errno = 0; errno = 0;
fprintf(stderr, "EOF\n"); fprintf(stderr, "EOF\n");
return 0; return 0;
} }
if (ret < 0) { if (ret < 0) {
if (errno != EAGAIN) if (errno != EAGAIN)
perror_wrapper("read"); perror_wrapper("read");
return 0; return 0;
} }
if (got_read == 0) { if (got_read == 0) {
// force blocking operation on further reads // force blocking operation on further reads
set_block(fd); set_block(fd);
} }
got_read += ret; got_read += ret;
} }
// fprintf(stderr, "read %d bytes\n", size); // fprintf(stderr, "read %d bytes\n", size);
return 1; return 1;
} }
int copy_fd_all(int fdout, int fdin) int copy_fd_all(int fdout, int fdin)
{ {
int ret; int ret;
char buf[4096]; char buf[4096];
for (;;) { for (;;) {
ret = read(fdin, buf, sizeof(buf)); ret = read(fdin, buf, sizeof(buf));
if (ret == -1 && errno == EINTR) if (ret == -1 && errno == EINTR)
continue; continue;
if (!ret) if (!ret)
break; break;
if (ret < 0) { if (ret < 0) {
perror_wrapper("read"); perror_wrapper("read");
return 0; return 0;
} }
if (!write_all(fdout, buf, ret)) { if (!write_all(fdout, buf, ret)) {
perror_wrapper("write"); perror_wrapper("write");
return 0; return 0;
} }
} }
return 1; return 1;
} }

@ -24,8 +24,8 @@
#include <libvchan.h> #include <libvchan.h>
struct buffer { struct buffer {
char *data; char *data;
int buflen; int buflen;
}; };
/* return codes for buffered writes */ /* return codes for buffered writes */
@ -48,7 +48,7 @@ int write_stdin(int fd, const char *data, int len, struct buffer *buffer);
int fork_and_flush_stdin(int fd, struct buffer *buffer); int fork_and_flush_stdin(int fd, struct buffer *buffer);
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd, void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
int *stderr_fd); int *stderr_fd);
void wait_for_vchan_or_argfd(libvchan_t *vchan, int max, fd_set * rdset, fd_set * wrset); void wait_for_vchan_or_argfd(libvchan_t *vchan, int max, fd_set * rdset, fd_set * wrset);
int read_vchan_all(libvchan_t *vchan, void *data, size_t size); int read_vchan_all(libvchan_t *vchan, void *data, size_t size);
int write_vchan_all(libvchan_t *vchan, const void *data, size_t size); int write_vchan_all(libvchan_t *vchan, const void *data, size_t size);

@ -35,32 +35,32 @@
#include <sys/types.h> #include <sys/types.h>
struct file_header { struct file_header {
unsigned int namelen; unsigned int namelen;
unsigned int mode; unsigned int mode;
unsigned long long filelen; unsigned long long filelen;
unsigned int atime; unsigned int atime;
unsigned int atime_nsec; unsigned int atime_nsec;
unsigned int mtime; unsigned int mtime;
unsigned int mtime_nsec; unsigned int mtime_nsec;
}; };
struct result_header { struct result_header {
uint32_t error_code; uint32_t error_code;
uint32_t _pad; uint32_t _pad;
uint64_t crc32; uint64_t crc32;
} __attribute__((packed)); } __attribute__((packed));
/* optional info about last processed file */ /* optional info about last processed file */
struct result_header_ext { struct result_header_ext {
uint32_t last_namelen; uint32_t last_namelen;
char last_name[0]; char last_name[0];
} __attribute__((packed)); } __attribute__((packed));
enum { enum {
COPY_FILE_OK, COPY_FILE_OK,
COPY_FILE_READ_EOF, COPY_FILE_READ_EOF,
COPY_FILE_READ_ERROR, COPY_FILE_READ_ERROR,
COPY_FILE_WRITE_ERROR COPY_FILE_WRITE_ERROR
}; };
/* feedback handling */ /* feedback handling */

@ -34,91 +34,91 @@ _Noreturn static void call_error_handler(const char *fmt, ...)
static int write_all_with_crc(int fd, const void *buf, int size) static int write_all_with_crc(int fd, const void *buf, int size)
{ {
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return write_all(fd, buf, size); return write_all(fd, buf, size);
} }
void notify_end_and_wait_for_result(void) void notify_end_and_wait_for_result(void)
{ {
struct file_header end_hdr; struct file_header end_hdr;
/* nofity end of transfer */ /* nofity end of transfer */
memset(&end_hdr, 0, sizeof(end_hdr)); memset(&end_hdr, 0, sizeof(end_hdr));
end_hdr.namelen = 0; end_hdr.namelen = 0;
end_hdr.filelen = 0; end_hdr.filelen = 0;
write_all_with_crc(1, &end_hdr, sizeof(end_hdr)); write_all_with_crc(1, &end_hdr, sizeof(end_hdr));
set_block(0); set_block(0);
wait_for_result(); wait_for_result();
} }
void wait_for_result(void) void wait_for_result(void)
{ {
struct result_header hdr; struct result_header hdr;
struct result_header_ext hdr_ext; struct result_header_ext hdr_ext;
char last_filename[MAX_PATH_LENGTH + 1]; char last_filename[MAX_PATH_LENGTH + 1];
char last_filename_prefix[] = "; Last file: "; char last_filename_prefix[] = "; Last file: ";
if (!read_all(0, &hdr, sizeof(hdr))) { if (!read_all(0, &hdr, sizeof(hdr))) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
// no result sent and stdin still open // no result sent and stdin still open
return; return;
} else { } else {
// other read error or EOF // other read error or EOF
exit(1); // hopefully remote has produced error message exit(1); // hopefully remote has produced error message
} }
} }
if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) { if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) {
// remote used old result_header struct // remote used old result_header struct
hdr_ext.last_namelen = 0; hdr_ext.last_namelen = 0;
} }
if (hdr_ext.last_namelen > MAX_PATH_LENGTH) { if (hdr_ext.last_namelen > MAX_PATH_LENGTH) {
// read only at most MAX_PATH_LENGTH chars // read only at most MAX_PATH_LENGTH chars
hdr_ext.last_namelen = MAX_PATH_LENGTH; hdr_ext.last_namelen = MAX_PATH_LENGTH;
} }
if (!read_all(0, last_filename, hdr_ext.last_namelen)) { if (!read_all(0, last_filename, hdr_ext.last_namelen)) {
fprintf(stderr, "Failed to get last filename\n"); fprintf(stderr, "Failed to get last filename\n");
hdr_ext.last_namelen = 0; hdr_ext.last_namelen = 0;
} }
last_filename[hdr_ext.last_namelen] = '\0'; last_filename[hdr_ext.last_namelen] = '\0';
if (!hdr_ext.last_namelen) if (!hdr_ext.last_namelen)
/* set prefix to empty string */ /* set prefix to empty string */
last_filename_prefix[0] = '\0'; last_filename_prefix[0] = '\0';
errno = hdr.error_code; errno = hdr.error_code;
if (hdr.error_code != 0) { if (hdr.error_code != 0) {
switch (hdr.error_code) { switch (hdr.error_code) {
case EEXIST: case EEXIST:
call_error_handler("File copy: not overwriting existing file. Clean QubesIncoming dir, and retry copy%s%s", last_filename_prefix, last_filename); call_error_handler("File copy: not overwriting existing file. Clean QubesIncoming dir, and retry copy%s%s", last_filename_prefix, last_filename);
break; break;
case EINVAL: case EINVAL:
call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename); call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename);
break; break;
case EDQUOT: case EDQUOT:
if (ignore_quota_error) { if (ignore_quota_error) {
/* skip also CRC check as sender and receiver might be /* skip also CRC check as sender and receiver might be
* desynchronized in this case */ * desynchronized in this case */
return; return;
} }
/* fall though */ /* fall though */
default: default:
call_error_handler("File copy: %s%s%s", call_error_handler("File copy: %s%s%s",
strerror(hdr.error_code), last_filename_prefix, last_filename); strerror(hdr.error_code), last_filename_prefix, last_filename);
} }
} }
if (hdr.crc32 != crc32_sum) { if (hdr.crc32 != crc32_sum) {
call_error_handler("File transfer failed: checksum mismatch"); call_error_handler("File transfer failed: checksum mismatch");
} }
} }
void write_headers(const struct file_header *hdr, const char *filename) void write_headers(const struct file_header *hdr, const char *filename)
{ {
if (!write_all_with_crc(1, hdr, sizeof(*hdr)) if (!write_all_with_crc(1, hdr, sizeof(*hdr))
|| !write_all_with_crc(1, filename, hdr->namelen)) { || !write_all_with_crc(1, filename, hdr->namelen)) {
set_block(0); set_block(0);
wait_for_result(); wait_for_result();
exit(1); exit(1);
} }
} }
int copy_file_with_crc(int outfd, int infd, long long size) { int copy_file_with_crc(int outfd, int infd, long long size) {
@ -127,100 +127,100 @@ int copy_file_with_crc(int outfd, int infd, long long size) {
int single_file_processor(const char *filename, const struct stat *st) int single_file_processor(const char *filename, const struct stat *st)
{ {
struct file_header hdr; struct file_header hdr;
int fd; int fd;
mode_t mode = st->st_mode; mode_t mode = st->st_mode;
hdr.namelen = strlen(filename) + 1; hdr.namelen = strlen(filename) + 1;
hdr.mode = mode; hdr.mode = mode;
hdr.atime = st->st_atim.tv_sec; hdr.atime = st->st_atim.tv_sec;
hdr.atime_nsec = st->st_atim.tv_nsec; hdr.atime_nsec = st->st_atim.tv_nsec;
hdr.mtime = st->st_mtim.tv_sec; hdr.mtime = st->st_mtim.tv_sec;
hdr.mtime_nsec = st->st_mtim.tv_nsec; hdr.mtime_nsec = st->st_mtim.tv_nsec;
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
int ret; int ret;
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) if (fd < 0)
call_error_handler("open %s", filename); call_error_handler("open %s", filename);
hdr.filelen = st->st_size; hdr.filelen = st->st_size;
write_headers(&hdr, filename); write_headers(&hdr, filename);
ret = copy_file(1, fd, hdr.filelen, &crc32_sum); ret = copy_file(1, fd, hdr.filelen, &crc32_sum);
if (ret != COPY_FILE_OK) { if (ret != COPY_FILE_OK) {
if (ret != COPY_FILE_WRITE_ERROR) if (ret != COPY_FILE_WRITE_ERROR)
call_error_handler("Copying file %s: %s", filename, call_error_handler("Copying file %s: %s", filename,
copy_file_status_to_str(ret)); copy_file_status_to_str(ret));
else { else {
set_block(0); set_block(0);
wait_for_result(); wait_for_result();
exit(1); exit(1);
} }
} }
close(fd); close(fd);
} }
if (S_ISDIR(mode)) { if (S_ISDIR(mode)) {
hdr.filelen = 0; hdr.filelen = 0;
write_headers(&hdr, filename); write_headers(&hdr, filename);
} }
if (S_ISLNK(mode)) { if (S_ISLNK(mode)) {
char name[st->st_size + 1]; char name[st->st_size + 1];
if (readlink(filename, name, sizeof(name)) != st->st_size) if (readlink(filename, name, sizeof(name)) != st->st_size)
call_error_handler("readlink %s", filename); call_error_handler("readlink %s", filename);
hdr.filelen = st->st_size; hdr.filelen = st->st_size;
write_headers(&hdr, filename); write_headers(&hdr, filename);
if (!write_all_with_crc(1, name, st->st_size)) { if (!write_all_with_crc(1, name, st->st_size)) {
set_block(0); set_block(0);
wait_for_result(); wait_for_result();
exit(1); exit(1);
} }
} }
// check for possible error from qfile-unpacker // check for possible error from qfile-unpacker
wait_for_result(); wait_for_result();
return 0; return 0;
} }
int do_fs_walk(const char *file, int ignore_symlinks) int do_fs_walk(const char *file, int ignore_symlinks)
{ {
char *newfile; char *newfile;
struct stat st; struct stat st;
struct dirent *ent; struct dirent *ent;
DIR *dir; DIR *dir;
if (lstat(file, &st)) if (lstat(file, &st))
call_error_handler("stat %s", file); call_error_handler("stat %s", file);
if (S_ISLNK(st.st_mode) && ignore_symlinks) if (S_ISLNK(st.st_mode) && ignore_symlinks)
return 0; return 0;
single_file_processor(file, &st); single_file_processor(file, &st);
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode))
return 0; return 0;
dir = opendir(file); dir = opendir(file);
if (!dir) if (!dir)
call_error_handler("opendir %s", file); call_error_handler("opendir %s", file);
while ((ent = readdir(dir))) { while ((ent = readdir(dir))) {
char *fname = ent->d_name; char *fname = ent->d_name;
if (!strcmp(fname, ".") || !strcmp(fname, "..")) if (!strcmp(fname, ".") || !strcmp(fname, ".."))
continue; continue;
if (asprintf(&newfile, "%s/%s", file, fname) >= 0) { if (asprintf(&newfile, "%s/%s", file, fname) >= 0) {
do_fs_walk(newfile, ignore_symlinks); do_fs_walk(newfile, ignore_symlinks);
free(newfile); free(newfile);
} else { } else {
fprintf(stderr, "asprintf failed\n"); fprintf(stderr, "asprintf failed\n");
exit(1); exit(1);
} }
} }
closedir(dir); closedir(dir);
// directory metadata is resent; this makes the code simple, // directory metadata is resent; this makes the code simple,
// and the atime/mtime is set correctly at the second time // and the atime/mtime is set correctly at the second time
single_file_processor(file, &st); single_file_processor(file, &st);
return 0; return 0;
} }
void qfile_pack_init(void) { void qfile_pack_init(void) {
crc32_sum = 0; crc32_sum = 0;
ignore_quota_error = 0; ignore_quota_error = 0;
// this will allow checking for possible feedback packet in the middle of transfer // this will allow checking for possible feedback packet in the middle of transfer
set_nonblock(0); set_nonblock(0);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
error_handler = NULL; error_handler = NULL;
} }

@ -28,51 +28,51 @@
int wait_for_vchan_or_argfd_once(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset) int wait_for_vchan_or_argfd_once(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset)
{ {
int vfd, ret; int vfd, ret;
struct timespec tv = { 1, 100000000 }; struct timespec tv = { 1, 100000000 };
sigset_t empty_set; sigset_t empty_set;
sigemptyset(&empty_set); sigemptyset(&empty_set);
vfd = libvchan_fd_for_select(ctrl); vfd = libvchan_fd_for_select(ctrl);
FD_SET(vfd, rdset); FD_SET(vfd, rdset);
if (vfd > max) if (vfd > max)
max = vfd; max = vfd;
max++; max++;
ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set); ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set);
if (ret < 0) { if (ret < 0) {
if (errno != EINTR) { if (errno != EINTR) {
perror("select"); perror("select");
exit(1); exit(1);
} else { } else {
FD_ZERO(rdset); FD_ZERO(rdset);
FD_ZERO(wrset); FD_ZERO(wrset);
fprintf(stderr, "eintr\n"); fprintf(stderr, "eintr\n");
return 1; return 1;
} }
} }
if (!libvchan_is_open(ctrl)) { if (!libvchan_is_open(ctrl)) {
fprintf(stderr, "libvchan_is_eof\n"); fprintf(stderr, "libvchan_is_eof\n");
exit(0); exit(0);
} }
if (FD_ISSET(vfd, rdset)) if (FD_ISSET(vfd, rdset))
// the following will never block; we need to do this to // the following will never block; we need to do this to
// clear libvchan_fd pending state // clear libvchan_fd pending state
libvchan_wait(ctrl); libvchan_wait(ctrl);
if (libvchan_data_ready(ctrl)) if (libvchan_data_ready(ctrl))
return 1; return 1;
return ret; return ret;
} }
void wait_for_vchan_or_argfd(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset) void wait_for_vchan_or_argfd(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset)
{ {
fd_set r = *rdset, w = *wrset; fd_set r = *rdset, w = *wrset;
do { do {
*rdset = r; *rdset = r;
*wrset = w; *wrset = w;
} }
while (wait_for_vchan_or_argfd_once(ctrl, max, rdset, wrset) == 0); while (wait_for_vchan_or_argfd_once(ctrl, max, rdset, wrset) == 0);
} }
int write_vchan_all(libvchan_t *vchan, const void *data, size_t size) { int write_vchan_all(libvchan_t *vchan, const void *data, size_t size) {

@ -29,45 +29,45 @@
int get_server_socket(const char *socket_address) int get_server_socket(const char *socket_address)
{ {
struct sockaddr_un sockname; struct sockaddr_un sockname;
int s; int s;
unlink(socket_address); unlink(socket_address);
s = socket(AF_UNIX, SOCK_STREAM, 0); s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) { if (s < 0) {
printf("socket() failed\n"); printf("socket() failed\n");
exit(1); exit(1);
} }
memset(&sockname, 0, sizeof(sockname)); memset(&sockname, 0, sizeof(sockname));
sockname.sun_family = AF_UNIX; sockname.sun_family = AF_UNIX;
strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path); strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path);
sockname.sun_path[sizeof sockname.sun_path - 1] = 0; sockname.sun_path[sizeof sockname.sun_path - 1] = 0;
if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) { if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) {
printf("bind() failed\n"); printf("bind() failed\n");
close(s); close(s);
exit(1); exit(1);
} }
// chmod(sockname.sun_path, 0666); // chmod(sockname.sun_path, 0666);
if (listen(s, 5) == -1) { if (listen(s, 5) == -1) {
perror("listen() failed\n"); perror("listen() failed\n");
close(s); close(s);
exit(1); exit(1);
} }
return s; return s;
} }
int do_accept(int s) int do_accept(int s)
{ {
struct sockaddr_un peer; struct sockaddr_un peer;
unsigned int addrlen; unsigned int addrlen;
int fd; int fd;
addrlen = sizeof(peer); addrlen = sizeof(peer);
fd = accept(s, (struct sockaddr *) &peer, &addrlen); fd = accept(s, (struct sockaddr *) &peer, &addrlen);
if (fd == -1) { if (fd == -1) {
perror("unix accept"); perror("unix accept");
exit(1); exit(1);
} }
return fd; return fd;
} }

@ -39,206 +39,206 @@ void send_status_and_crc(int code, const char *last_filename);
void do_exit(int code, const char *last_filename) void do_exit(int code, const char *last_filename)
{ {
close(0); close(0);
send_status_and_crc(code, last_filename); send_status_and_crc(code, last_filename);
exit(code); exit(code);
} }
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit) void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit)
{ {
bytes_limit = new_bytes_limit; bytes_limit = new_bytes_limit;
files_limit = new_files_limit; files_limit = new_files_limit;
} }
void set_verbose(int value) void set_verbose(int value)
{ {
verbose = value; verbose = value;
} }
void set_procfs_fd(int value) void set_procfs_fd(int value)
{ {
procdir_fd = value; procdir_fd = value;
use_tmpfile = 1; use_tmpfile = 1;
} }
unsigned long crc32_sum = 0; unsigned long crc32_sum = 0;
int read_all_with_crc(int fd, void *buf, int size) { int read_all_with_crc(int fd, void *buf, int size) {
int ret; int ret;
ret = read_all(fd, buf, size); ret = read_all(fd, buf, size);
if (ret) if (ret)
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
return ret; return ret;
} }
void send_status_and_crc(int code, const char *last_filename) { void send_status_and_crc(int code, const char *last_filename) {
struct result_header hdr; struct result_header hdr;
struct result_header_ext hdr_ext; struct result_header_ext hdr_ext;
int saved_errno; int saved_errno;
saved_errno = errno; saved_errno = errno;
hdr.error_code = code; hdr.error_code = code;
hdr.crc32 = crc32_sum; hdr.crc32 = crc32_sum;
if (!write_all(1, &hdr, sizeof(hdr))) if (!write_all(1, &hdr, sizeof(hdr)))
perror("write status"); perror("write status");
if (last_filename) { if (last_filename) {
hdr_ext.last_namelen = strlen(last_filename); hdr_ext.last_namelen = strlen(last_filename);
if (!write_all(1, &hdr_ext, sizeof(hdr_ext))) if (!write_all(1, &hdr_ext, sizeof(hdr_ext)))
perror("write status ext"); perror("write status ext");
if (!write_all(1, last_filename, hdr_ext.last_namelen)) if (!write_all(1, last_filename, hdr_ext.last_namelen))
perror("write last_filename"); perror("write last_filename");
} }
errno = saved_errno; errno = saved_errno;
} }
void fix_times_and_perms(struct file_header *untrusted_hdr, void fix_times_and_perms(struct file_header *untrusted_hdr,
const char *untrusted_name) const char *untrusted_name)
{ {
struct timeval times[2] = struct timeval times[2] =
{ {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000}, {
{untrusted_hdr->mtime, {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
untrusted_hdr->mtime_nsec / 1000} {untrusted_hdr->mtime, untrusted_hdr->mtime_nsec / 1000}
}; };
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */ if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
if (utimes(untrusted_name, times)) /* as above */ if (utimes(untrusted_name, times)) /* as above */
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
} }
void process_one_file_reg(struct file_header *untrusted_hdr, void process_one_file_reg(struct file_header *untrusted_hdr,
const char *untrusted_name) const char *untrusted_name)
{ {
int ret; int ret;
int fdout = -1; int fdout = -1;
/* make the file inaccessible until fully written */ /* make the file inaccessible until fully written */
if (use_tmpfile) { if (use_tmpfile) {
fdout = open(".", O_WRONLY | O_TMPFILE, 0700); fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
if (fdout < 0) { if (fdout < 0) {
if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */ if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */
errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */ errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */
use_tmpfile = 0; use_tmpfile = 0;
else else
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
} }
} }
if (fdout < 0) if (fdout < 0)
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */ fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
if (fdout < 0) if (fdout < 0)
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
/* sizes are signed elsewhere */ /* sizes are signed elsewhere */
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit)) if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
do_exit(EDQUOT, untrusted_name); do_exit(EDQUOT, untrusted_name);
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen) if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
do_exit(EDQUOT, untrusted_name); do_exit(EDQUOT, untrusted_name);
total_bytes += untrusted_hdr->filelen; total_bytes += untrusted_hdr->filelen;
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
if (ret != COPY_FILE_OK) { if (ret != COPY_FILE_OK) {
if (ret == COPY_FILE_READ_EOF if (ret == COPY_FILE_READ_EOF
|| ret == COPY_FILE_READ_ERROR) || ret == COPY_FILE_READ_ERROR)
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message
else else
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
} }
if (use_tmpfile) { if (use_tmpfile) {
char fd_str[7]; char fd_str[7];
snprintf(fd_str, sizeof(fd_str), "%d", fdout); snprintf(fd_str, sizeof(fd_str), "%d", fdout);
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0) if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
} }
close(fdout); close(fdout);
fix_times_and_perms(untrusted_hdr, untrusted_name); fix_times_and_perms(untrusted_hdr, untrusted_name);
} }
void process_one_file_dir(struct file_header *untrusted_hdr, void process_one_file_dir(struct file_header *untrusted_hdr,
const char *untrusted_name) const char *untrusted_name)
{ {
// fix perms only when the directory is sent for the second time // fix perms only when the directory is sent for the second time
// it allows to transfer r.x directory contents, as we create it rwx initially // it allows to transfer r.x directory contents, as we create it rwx initially
struct stat buf; struct stat buf;
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */ if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
return; return;
if (errno != EEXIST) if (errno != EEXIST)
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
if (stat(untrusted_name,&buf) < 0) if (stat(untrusted_name,&buf) < 0)
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
total_bytes += buf.st_size; total_bytes += buf.st_size;
/* size accumulated after the fact, so don't check limit here */ /* size accumulated after the fact, so don't check limit here */
fix_times_and_perms(untrusted_hdr, untrusted_name); fix_times_and_perms(untrusted_hdr, untrusted_name);
} }
void process_one_file_link(struct file_header *untrusted_hdr, void process_one_file_link(struct file_header *untrusted_hdr,
const char *untrusted_name) const char *untrusted_name)
{ {
char untrusted_content[MAX_PATH_LENGTH]; char untrusted_content[MAX_PATH_LENGTH];
unsigned int filelen; unsigned int filelen;
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1) if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, untrusted_name); do_exit(ENAMETOOLONG, untrusted_name);
filelen = untrusted_hdr->filelen; /* sanitized above */ filelen = untrusted_hdr->filelen; /* sanitized above */
total_bytes += filelen; total_bytes += filelen;
if (bytes_limit && total_bytes > bytes_limit) if (bytes_limit && total_bytes > bytes_limit)
do_exit(EDQUOT, untrusted_name); do_exit(EDQUOT, untrusted_name);
if (!read_all_with_crc(0, untrusted_content, filelen)) if (!read_all_with_crc(0, untrusted_content, filelen))
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message
untrusted_content[filelen] = 0; untrusted_content[filelen] = 0;
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */ if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
do_exit(errno, untrusted_name); do_exit(errno, untrusted_name);
} }
void process_one_file(struct file_header *untrusted_hdr) void process_one_file(struct file_header *untrusted_hdr)
{ {
unsigned int namelen; unsigned int namelen;
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1) if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */ do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */
namelen = untrusted_hdr->namelen; /* sanitized above */ namelen = untrusted_hdr->namelen; /* sanitized above */
if (!read_all_with_crc(0, untrusted_namebuf, namelen)) if (!read_all_with_crc(0, untrusted_namebuf, namelen))
do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message
untrusted_namebuf[namelen] = 0; untrusted_namebuf[namelen] = 0;
if (S_ISREG(untrusted_hdr->mode)) if (S_ISREG(untrusted_hdr->mode))
process_one_file_reg(untrusted_hdr, untrusted_namebuf); process_one_file_reg(untrusted_hdr, untrusted_namebuf);
else if (S_ISLNK(untrusted_hdr->mode)) else if (S_ISLNK(untrusted_hdr->mode))
process_one_file_link(untrusted_hdr, untrusted_namebuf); process_one_file_link(untrusted_hdr, untrusted_namebuf);
else if (S_ISDIR(untrusted_hdr->mode)) else if (S_ISDIR(untrusted_hdr->mode))
process_one_file_dir(untrusted_hdr, untrusted_namebuf); process_one_file_dir(untrusted_hdr, untrusted_namebuf);
else else
do_exit(EINVAL, untrusted_namebuf); do_exit(EINVAL, untrusted_namebuf);
if (verbose && !S_ISDIR(untrusted_hdr->mode)) if (verbose && !S_ISDIR(untrusted_hdr->mode))
fprintf(stderr, "%s\n", untrusted_namebuf); fprintf(stderr, "%s\n", untrusted_namebuf);
} }
int do_unpack(void) int do_unpack(void)
{ {
struct file_header untrusted_hdr; struct file_header untrusted_hdr;
#ifdef HAVE_SYNCFS #ifdef HAVE_SYNCFS
int cwd_fd; int cwd_fd;
int saved_errno; int saved_errno;
#endif #endif
total_bytes = total_files = 0; total_bytes = total_files = 0;
/* initialize checksum */ /* initialize checksum */
crc32_sum = 0; crc32_sum = 0;
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) { while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
/* check for end of transfer marker */ /* check for end of transfer marker */
if (untrusted_hdr.namelen == 0) { if (untrusted_hdr.namelen == 0) {
errno = 0; errno = 0;
break; break;
} }
total_files++; total_files++;
if (files_limit && total_files > files_limit) if (files_limit && total_files > files_limit)
do_exit(EDQUOT, untrusted_namebuf); do_exit(EDQUOT, untrusted_namebuf);
process_one_file(&untrusted_hdr); process_one_file(&untrusted_hdr);
} }
#ifdef HAVE_SYNCFS #ifdef HAVE_SYNCFS
saved_errno = errno; saved_errno = errno;
cwd_fd = open(".", O_RDONLY); cwd_fd = open(".", O_RDONLY);
if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0) if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0)
errno = saved_errno; errno = saved_errno;
#endif #endif
send_status_and_crc(errno, untrusted_namebuf); send_status_and_crc(errno, untrusted_namebuf);
return errno; return errno;
} }

@ -34,86 +34,86 @@ reports that "fd" is writable. Write as much as possible to fd.
*/ */
int flush_client_data(int fd, struct buffer *buffer) int flush_client_data(int fd, struct buffer *buffer)
{ {
int ret; int ret;
int len; int len;
for (;;) { for (;;) {
len = buffer_len(buffer); len = buffer_len(buffer);
if (!len) { if (!len) {
return WRITE_STDIN_OK; return WRITE_STDIN_OK;
} }
if (len > MAX_DATA_CHUNK) if (len > MAX_DATA_CHUNK)
len = MAX_DATA_CHUNK; len = MAX_DATA_CHUNK;
ret = write(fd, buffer_data(buffer), len); ret = write(fd, buffer_data(buffer), len);
if (ret == -1) { if (ret == -1) {
if (errno != EAGAIN) { if (errno != EAGAIN) {
return WRITE_STDIN_ERROR; return WRITE_STDIN_ERROR;
} else } else
return WRITE_STDIN_BUFFERED; return WRITE_STDIN_BUFFERED;
} }
// we previously called buffer_remove(buffer, len) // we previously called buffer_remove(buffer, len)
// it will be wrong if we change MAX_DATA_CHUNK to something large // it will be wrong if we change MAX_DATA_CHUNK to something large
// as pipes writes are atomic only to PIPE_MAX limit // as pipes writes are atomic only to PIPE_MAX limit
buffer_remove(buffer, ret); buffer_remove(buffer, ret);
} }
} }
/* /*
Write "len" bytes from "data" to "fd". If not all written, buffer the rest * Write "len" bytes from "data" to "fd". If not all written, buffer the rest
to "buffer". * to "buffer".
*/ */
int write_stdin(int fd, const char *data, int len, struct buffer *buffer) int write_stdin(int fd, const char *data, int len, struct buffer *buffer)
{ {
int ret; int ret;
int written = 0; int written = 0;
if (buffer_len(buffer)) { if (buffer_len(buffer)) {
buffer_append(buffer, data, len); buffer_append(buffer, data, len);
return WRITE_STDIN_BUFFERED; return WRITE_STDIN_BUFFERED;
} }
while (written < len) { while (written < len) {
ret = write(fd, data + written, len - written); ret = write(fd, data + written, len - written);
if (ret == 0) { if (ret == 0) {
perror("write_stdin: write returns 0 ???"); perror("write_stdin: write returns 0 ???");
exit(1); exit(1);
} }
if (ret == -1) { if (ret == -1) {
if (errno != EAGAIN) if (errno != EAGAIN)
return WRITE_STDIN_ERROR; return WRITE_STDIN_ERROR;
buffer_append(buffer, data + written, buffer_append(buffer, data + written,
len - written); len - written);
return WRITE_STDIN_BUFFERED; return WRITE_STDIN_BUFFERED;
} }
written += ret; written += ret;
} }
return WRITE_STDIN_OK; return WRITE_STDIN_OK;
} }
/* /*
Data feed process has exited, so we need to clear all control structures for * Data feed process has exited, so we need to clear all control structures for
the client. However, if we have buffered data for the client (which is rare btw), * the client. However, if we have buffered data for the client (which is rare btw),
fire&forget a separate process to flush them. * fire&forget a separate process to flush them.
*/ */
int fork_and_flush_stdin(int fd, struct buffer *buffer) int fork_and_flush_stdin(int fd, struct buffer *buffer)
{ {
int i; int i;
if (!buffer_len(buffer)) if (!buffer_len(buffer))
return 0; return 0;
switch (fork()) { switch (fork()) {
case -1: case -1:
perror("fork"); perror("fork");
exit(1); exit(1);
case 0: case 0:
break; break;
default: default:
return 1; return 1;
} }
for (i = 0; i < MAX_FDS; i++) for (i = 0; i < MAX_FDS; i++)
if (i != fd && i != 2) if (i != fd && i != 2)
close(i); close(i);
set_block(fd); set_block(fd);
write_all(fd, buffer_data(buffer), buffer_len(buffer)); write_all(fd, buffer_data(buffer), buffer_len(buffer));
_exit(0); _exit(0);
} }

@ -1,5 +1,8 @@
#!/bin/bash #!/bin/bash
shopt -s nullglob
export LC_CTYPE=en_US.UTF-8 export LC_CTYPE=en_US.UTF-8
NAME=${DEVNAME#/dev/} NAME=${DEVNAME#/dev/}
DESC="`echo "${ID_MODEL} (${ID_FS_LABEL})" | iconv -f utf8 -t ascii//TRANSLIT`" DESC="`echo "${ID_MODEL} (${ID_FS_LABEL})" | iconv -f utf8 -t ascii//TRANSLIT`"
@ -8,6 +11,10 @@ MODE=w
QDB_KEY="/qubes-block-devices/$NAME" QDB_KEY="/qubes-block-devices/$NAME"
xs_remove() { xs_remove() {
if is_attached /sys$DEVPATH; then
return 0
fi
if [ "$QUBES_EXPOSED" == "1" ]; then if [ "$QUBES_EXPOSED" == "1" ]; then
qubesdb-rm "$QDB_KEY/" qubesdb-rm "$QDB_KEY/"
qubesdb-write /qubes-block-devices '' qubesdb-write /qubes-block-devices ''
@ -15,26 +22,84 @@ xs_remove() {
echo QUBES_EXPOSED=0 echo QUBES_EXPOSED=0
} }
# Ignore mounted... is_used() {
if fgrep -q $DEVNAME /proc/mounts; then local sys_devpath=$1
xs_remove local devname=$(grep ^DEVNAME= $sys_devpath/uevent | cut -f 2 -d =)
exit 0 # mounted; or enabled swap
if lsblk -dnr -o MOUNTPOINT "/dev/$devname" | grep -q .; then
return 0
fi
# part of other device-mapper
if [ -n "`ls -A $sys_devpath/holders 2> /dev/null`" ]; then
return 0
fi
# open device-mapper device
if [ -f "$sys_devpath/dm/name" ] && \
/sbin/dmsetup info "$(cat $sys_devpath/dm/name)" |\
grep -q "^Open count:.*[1-9]"; then
return 0
fi
return 1
}
# communicate with xenstored through socket in dom0
# trying to access xenstore before xenstored is started, hang forever (in
# non-killable state), so better fail ('-s' in VM if /proc/xen isn't mounted
# yet) than hang dom0 boot
if [ ! -r /proc/xen/capabilities ] || grep -q control_d /proc/xen/capabilities; then
XENSTORE_LS="xenstore-ls -s"
else
XENSTORE_LS="xenstore-ls"
fi fi
# ... and used by device-mapper is_attached() {
if [ -n "`ls -A /sys/$DEVPATH/holders 2> /dev/null`" ]; then dev_hex=$(stat -c %t:%T /dev/$(basename $1))
xs_remove $XENSTORE_LS backend/vbd | grep -q "physical-device = \"$dev_hex\""
exit 0 }
# update info about parent devices, if any:
if [ -f /sys$DEVPATH/partition ]; then
parent=$(dirname $(readlink -f /sys$DEVPATH))
udevadm trigger \
--property-match=DEVPATH=/$(realpath --relative-to=/sys $parent)
# if parent device is already attached, skip its partitions
if is_attached $parent; then
xs_remove
exit 0
fi
fi fi
# ... and used device-mapper devices
if [ -n "$DM_NAME" ] && /sbin/dmsetup info "$DM_NAME" | grep -q "^Open count:.*[1-9]"; then # and underlying devices of device-mapper (if any)
for dev in /sys$DEVPATH/slaves/*; do
udevadm trigger \
--property-match=DEVPATH=/$(realpath --relative-to=/sys $dev)
done
# then take care of this device:
# device itself is already used
if is_used /sys$DEVPATH; then
xs_remove xs_remove
exit 0 exit 0
fi fi
# ... and "empty" loop devices
# or one of its partitions is used
# or already attached (prevent attaching both device and its partition(s) at
# the same time)
for part in /sys$DEVPATH/$NAME*; do
if [ -d $part ]; then
if is_used $part || is_attached $part; then
xs_remove
exit 0
fi
fi
done
# or "empty" loop device
if [ "$MAJOR" -eq 7 -a ! -d /sys/$DEVPATH/loop ]; then if [ "$MAJOR" -eq 7 -a ! -d /sys/$DEVPATH/loop ]; then
xs_remove xs_remove
exit 0 exit 0
fi fi
# ... and temporary devices used during VM startup # ... and temporary devices used during VM startup
if [[ "$NAME" = 'loop'* ]] && \ if [[ "$NAME" = 'loop'* ]] && \
[[ "`cat /sys/block/${NAME%p*}/loop/backing_file`" = \ [[ "`cat /sys/block/${NAME%p*}/loop/backing_file`" = \

@ -26,6 +26,11 @@ device_detach() {
xenstore-rm $xs_path xenstore-rm $xs_path
} }
# update info about underlying devices of device-mapper (if any)
# at this stage device-mapper is already removed, so can't check what devices
# were used there
udevadm trigger --subsystem-match=block
for XS_DEV_PATH in `xenstore-ls -f backend/vbd | grep 'backend/vbd/[0-9]*/[0-9]* ' | cut -f 1 -d ' '`; do for XS_DEV_PATH in `xenstore-ls -f backend/vbd | grep 'backend/vbd/[0-9]*/[0-9]* ' | cut -f 1 -d ' '`; do
CUR_DEVICE=`xenstore-read "$XS_DEV_PATH/params"` CUR_DEVICE=`xenstore-read "$XS_DEV_PATH/params"`
if [ "$CUR_DEVICE" == "$DEVNAME" ]; then if [ "$CUR_DEVICE" == "$DEVNAME" ]; then

@ -1 +1 @@
3.1.8 3.1.10

Loading…
Cancel
Save