Fix up device name on Windows.
[dcpomatic.git] / src / tools / dcpomatic_dist_writer.cc
index 08e5a109ea74c626ccad5281bd2ad3c06af2c5cd..404136878eb811f74f7df478a64c92710379deee 100644 (file)
 #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>
@@ -32,29 +34,51 @@ extern "C" {
 #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
@@ -118,8 +142,7 @@ write (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total
                }
                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);
@@ -156,8 +179,7 @@ read (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total_
                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);
@@ -174,13 +196,9 @@ static
 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();
 
@@ -195,7 +213,9 @@ copy (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total_
                }
        } 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);
                }
@@ -205,10 +225,11 @@ copy (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total_
 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;
@@ -218,7 +239,7 @@ write ()
        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());
@@ -228,6 +249,7 @@ write ()
        if (!bd) {
                throw CopyError ("Failed to open drive", 0);
        }
+       LOG_DIST_NC ("Opened drive");
 
        struct ext4_mbr_parts parts;
        parts.division[0] = 100;
@@ -245,8 +267,9 @@ write ()
        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) {
@@ -254,12 +277,16 @@ write ()
        }
 
        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])) {
@@ -274,25 +301,33 @@ write ()
        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/");
@@ -300,58 +335,70 @@ write ()
                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 ();