#include "lib/exceptions.h"
#include "lib/cross.h"
#include "lib/digester.h"
+#include "lib/file_log.h"
+#include "lib/dcpomatic_log.h"
+#include "lib/nanomsg.h"
extern "C" {
-#include <lwext4/file_dev.h>
#include <lwext4/ext4_mbr.h>
#include <lwext4/ext4_fs.h>
#include <lwext4/ext4_mkfs.h>
#include <lwext4/ext4_debug.h>
#include <lwext4/ext4.h>
}
-#ifndef WIN32
+
+#ifdef DCPOMATIC_POSIX
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <linux/fs.h>
#endif
+
+#ifdef DCPOMATIC_OSX
+#undef nil
+#endif
+
+#ifdef DCPOMATIC_LINUX
+#include <linux/fs.h>
#include <polkit/polkit.h>
+extern "C" {
+#include <lwext4/file_dev.h>
+}
+#include <poll.h>
+#endif
+
+#ifdef DCPOMATIC_WINDOWS
+extern "C" {
+#include <lwext4/file_windows.h>
+}
+#endif
+
#include <glibmm.h>
#include <unistd.h>
#include <sys/types.h>
-#include <poll.h>
#include <boost/filesystem.hpp>
#include <iostream>
-using std::cout;
using std::cin;
using std::min;
using std::string;
+using std::runtime_error;
+using boost::optional;
+#ifdef DCPOMATIC_LINUX
static PolkitAuthority* polkit_authority = 0;
+#endif
static boost::filesystem::path dcp_path;
static std::string device;
static uint64_t const block_size = 4096;
+static Nanomsg* nanomsg = 0;
static
void
}
remaining -= this_time;
total_remaining -= this_time;
- cout << DIST_WRITER_PROGRESS "\n" << (1 - float(total_remaining) / total) << "\n";
- cout.flush ();
+ nanomsg->send(String::compose(DIST_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)));
}
fclose (in);
digester.add (buffer, this_time);
remaining -= this_time;
total_remaining -= this_time;
- cout << DIST_WRITER_PROGRESS "\n" << (1 - float(total_remaining) / total) << "\n";
- cout.flush ();
+ nanomsg->send(String::compose(DIST_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)));
}
ext4_fclose (&in);
void
copy (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total_remaining, uint64_t total)
{
- using namespace boost::filesystem;
+ LOG_DIST ("Copy %1 -> %2", from.string(), to.string());
- /* XXX: this is a hack. We are going to "treat" every byte twice; write it, and then verify it. Double the
- * bytes totals so that progress works itself out (assuming write is the same speed as read).
- */
- total_remaining *= 2;
- total *= 2;
+ using namespace boost::filesystem;
path const cr = to / from.filename();
}
} else {
string const write_digest = write (from, cr, total_remaining, total);
+ LOG_DIST ("Wrote %1 %2 with %3", from.string(), cr.string(), write_digest);
string const read_digest = read (from, cr, total_remaining, total);
+ LOG_DIST ("Read %1 %2 with %3", from.string(), cr.string(), write_digest);
if (write_digest != read_digest) {
throw VerifyError ("Hash of written data is incorrect", 0);
}
static
void
write ()
+try
{
// ext4_dmask_set (DEBUG_ALL);
- cout << "U\n";
+ nanomsg->send("U\n");
/* We rely on static initialization for these */
static struct ext4_fs fs;
info.journal = false;
#ifdef WIN32
- file_windows_name_set(WINDOWS_DRIVE);
+ file_windows_name_set(device.c_str());
struct ext4_blockdev* bd = file_windows_dev_get();
#else
file_dev_name_set (device.c_str());
if (!bd) {
throw CopyError ("Failed to open drive", 0);
}
+ LOG_DIST_NC ("Opened drive");
struct ext4_mbr_parts parts;
parts.division[0] = 100;
if (r) {
throw CopyError ("Failed to write MBR", r);
}
+ LOG_DIST_NC ("Wrote MBR");
-#ifdef WIN32
+#ifdef DCPOMATIC_WINDOWS
struct ext4_mbr_bdevs bdevs;
r = ext4_mbr_scan (bd, &bdevs);
if (r != EOK) {
}
file_windows_partition_set (bdevs.partitions[0].part_offset, bdevs.partitions[0].part_size);
-#else
+#endif
+
+#ifdef DCPOMATIC_LINUX
/* Re-read the partition table */
int fd = open(device.c_str(), O_RDONLY);
ioctl(fd, BLKRRPART, NULL);
close(fd);
+#endif
+#ifdef DCPOMATIC_POSIX
string partition = device;
/* XXX: don't know if this logic is sensible */
if (partition.size() > 0 && isdigit(partition[partition.length() - 1])) {
if (!bd) {
throw CopyError ("Failed to open partition", 0);
}
+ LOG_DIST_NC ("Opened partition");
r = ext4_mkfs(&fs, bd, &info, F_SET_EXT4);
if (r != EOK) {
throw CopyError ("Failed to make filesystem", r);
}
+ LOG_DIST_NC ("Made filesystem");
r = ext4_device_register(bd, "ext4_fs");
if (r != EOK) {
throw CopyError ("Failed to register device", r);
}
+ LOG_DIST_NC ("Registered device");
r = ext4_mount("ext4_fs", "/mp/", false);
if (r != EOK) {
throw CopyError ("Failed to mount device", r);
}
+ LOG_DIST_NC ("Mounted device");
uint64_t total_bytes = 0;
count (dcp_path, total_bytes);
+ /* XXX: this is a hack. We are going to "treat" every byte twice; write it, and then verify it. Double the
+ * bytes totals so that progress works itself out (assuming write is the same speed as read).
+ */
+ total_bytes *= 2;
copy (dcp_path, "/mp", total_bytes, total_bytes);
r = ext4_umount("/mp/");
throw CopyError ("Failed to unmount device", r);
}
- cout << DIST_WRITER_OK "\n";
- cout.flush ();
+ nanomsg->send(DIST_WRITER_OK "\n");
+} catch (CopyError& e) {
+ nanomsg->send(String::compose(DIST_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number()));
+} catch (VerifyError& e) {
+ nanomsg->send(String::compose(DIST_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number()));
}
+#ifdef DCPOMATIC_LINUX
static
void
polkit_callback (GObject *, GAsyncResult* res, gpointer)
{
PolkitAuthorizationResult* result = polkit_authority_check_authorization_finish (polkit_authority, res, 0);
if (result && polkit_authorization_result_get_is_authorized(result)) {
- try {
- write ();
- } catch (CopyError& e) {
- cout << DIST_WRITER_ERROR "\n" << e.message() << "\n" << e.number() << "\n";
- cout.flush ();
- } catch (VerifyError& e) {
- cout << DIST_WRITER_ERROR "\n" << e.message() << "\n" << e.number() << "\n";
- cout.flush ();
- }
+ write ();
}
if (result) {
g_object_unref (result);
}
}
+#endif
bool
idle ()
{
- struct pollfd input[1] = { { fd: 0, events: POLLIN, revents: 0 } };
- int const r = poll (input, 1, 0);
- if (r > 0 && (input[0].revents & POLLIN)) {
- string s;
- getline (cin, s);
- if (s.empty()) {
- return true;
- }
- dcp_path = s;
- getline (cin, s);
- device = "/dev/" + s;
+ optional<string> s = nanomsg->nonblocking_get ();
+ if (!s) {
+ return true;
+ }
- polkit_authority = polkit_authority_get_sync (0, 0);
- PolkitSubject* subject = polkit_unix_process_new (getppid());
- polkit_authority_check_authorization (
+ dcp_path = *s;
+ device = nanomsg->blocking_get();
+
+ LOG_DIST ("Here we go writing %1 to %2", dcp_path, device);
+
+#ifdef DCPOMATIC_LINUX
+ polkit_authority = polkit_authority_get_sync (0, 0);
+ PolkitSubject* subject = polkit_unix_process_new (getppid());
+ polkit_authority_check_authorization (
polkit_authority, subject, "com.dcpomatic.write-drive", 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, 0, polkit_callback, 0
);
- }
+#else
+ write ();
+#endif
return true;
}
int
main ()
{
+ /* XXX: this is a hack, but I expect we'll need logs and I'm not sure if there's
+ * a better place to put them.
+ */
+ dcpomatic_log.reset(new FileLog(config_path() / "dist_writer.log"));
+ dcpomatic_log->set_types (dcpomatic_log->types() | LogEntry::TYPE_DIST);
+ LOG_DIST_NC("dcpomatic_dist_writer started");
+
+ try {
+ nanomsg = new Nanomsg (false);
+ } catch (runtime_error& e) {
+ LOG_DIST_NC("Could not set up nanomsg socket");
+ exit (EXIT_FAILURE);
+ }
+
Glib::RefPtr<Glib::MainLoop> ml = Glib::MainLoop::create ();
Glib::signal_timeout().connect(sigc::ptr_fun(&idle), 500);
ml->run ();