From 350afcbc40fffd8c8780180e153a2ee91088f562 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 9 Apr 2020 00:58:42 +0200 Subject: [PATCH] Tidy up nanomsg class API; add unmounting for Linux. --- src/lib/copy_to_drive_job.cc | 29 +++++--- src/lib/cross.h | 4 ++ src/lib/cross_common.cc | 2 +- src/lib/cross_linux.cc | 46 +++++++++--- src/lib/cross_osx.cc | 9 +++ src/lib/exceptions.cc | 13 +++- src/lib/exceptions.h | 18 ++++- src/lib/nanomsg.cc | 54 ++++++-------- src/lib/nanomsg.h | 19 ++--- src/tools/dcpomatic_disk.cc | 41 ++++++++--- src/tools/dcpomatic_disk_writer.cc | 109 +++++++++++++++++++---------- src/wx/try_unmount_dialog.cc | 42 +++++++++++ src/wx/try_unmount_dialog.h | 27 +++++++ src/wx/wscript | 1 + 14 files changed, 300 insertions(+), 114 deletions(-) create mode 100644 src/wx/try_unmount_dialog.cc create mode 100644 src/wx/try_unmount_dialog.h diff --git a/src/lib/copy_to_drive_job.cc b/src/lib/copy_to_drive_job.cc index fe35daba6..fcac7e41b 100644 --- a/src/lib/copy_to_drive_job.cc +++ b/src/lib/copy_to_drive_job.cc @@ -37,6 +37,7 @@ using std::string; using std::cout; using std::min; using boost::shared_ptr; +using boost::optional; using dcp::raw_convert; CopyToDriveJob::CopyToDriveJob (boost::filesystem::path dcp, Drive drive, Nanomsg& nanomsg) @@ -63,30 +64,36 @@ CopyToDriveJob::json_name () const void CopyToDriveJob::run () { - if (!_nanomsg.nonblocking_send(String::compose(DISK_WRITER_WRITE "\n%1\n%2\n", _dcp.string(), _drive.internal_name()))) { - throw CopyError ("Could not communicate with writer process", 0); + if (!_nanomsg.send(String::compose(DISK_WRITER_WRITE "\n%1\n%2\n", _dcp.string(), _drive.internal_name()), 2000)) { + throw CommunicationFailedError (); } bool formatting = false; while (true) { - string s = _nanomsg.blocking_get (); - if (s == DISK_WRITER_OK) { + optional s = _nanomsg.receive (10000); + if (!s) { + continue; + } + if (*s == DISK_WRITER_OK) { set_state (FINISHED_OK); return; - } else if (s == DISK_WRITER_ERROR) { - string const m = _nanomsg.blocking_get (); - string const n = _nanomsg.blocking_get (); - throw CopyError (m, raw_convert(n)); - } else if (s == DISK_WRITER_FORMATTING) { + } else if (*s == DISK_WRITER_ERROR) { + optional const m = _nanomsg.receive (500); + optional const n = _nanomsg.receive (500); + throw CopyError (m.get_value_or("Unknown"), raw_convert(n.get_value_or("0"))); + } else if (*s == DISK_WRITER_FORMATTING) { sub ("Formatting drive"); set_progress_unknown (); formatting = true; - } else if (s == DISK_WRITER_PROGRESS) { + } else if (*s == DISK_WRITER_PROGRESS) { if (formatting) { sub ("Copying DCP"); formatting = false; } - set_progress (raw_convert(_nanomsg.blocking_get())); + optional progress = _nanomsg.receive (500); + if (progress) { + set_progress (raw_convert(*progress)); + } } } } diff --git a/src/lib/cross.h b/src/lib/cross.h index 6d3c2bd2e..7bbb394a1 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -124,5 +124,9 @@ private: }; std::vector get_drives (); +/** Unmount any mounted partitions on a drive. + * @return true on success, false on failure. + */ +bool unmount_drive (std::string drive); #endif diff --git a/src/lib/cross_common.cc b/src/lib/cross_common.cc index b3a39402a..10ffb0677 100644 --- a/src/lib/cross_common.cc +++ b/src/lib/cross_common.cc @@ -46,6 +46,6 @@ Drive::description () const name = _("Unknown"); } - return String::compose("%1 (%2 GB) [%3]", name, gb, _internal_name); + return String::compose(_("%1 (%2 GB) [%3]"), name, gb, _internal_name); } diff --git a/src/lib/cross_linux.cc b/src/lib/cross_linux.cc index 8c81c5008..14a7e5b47 100644 --- a/src/lib/cross_linux.cc +++ b/src/lib/cross_linux.cc @@ -24,6 +24,7 @@ #include "dcpomatic_log.h" #include "config.h" #include "exceptions.h" +#include "dcpomatic_log.h" #include #include extern "C" { @@ -37,6 +38,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -256,25 +258,34 @@ running_32_on_64 () return false; } -vector -get_drives () +vector > +get_mounts (string prefix) { - vector drives; + vector > mounts; - using namespace boost::filesystem; - list mounted_devices; std::ifstream f("/proc/mounts"); string line; while (f.good()) { getline(f, line); vector bits; boost::algorithm::split (bits, line, boost::is_any_of(" ")); - if (bits.size() > 0 && boost::algorithm::starts_with(bits[0], "/dev/")) { - mounted_devices.push_back(bits[0]); - LOG_DISK("Mounted device %1", bits[0]); + if (bits.size() > 1 && boost::algorithm::starts_with(bits[0], prefix)) { + mounts.push_back(make_pair(bits[0], bits[1])); + LOG_DISK("Found mounted device %1 from prefix %2", bits[0], prefix); } } + return mounts; +} + +vector +get_drives () +{ + vector drives; + + using namespace boost::filesystem; + vector > mounted_devices = get_mounts("/dev/"); + for (directory_iterator i = directory_iterator("/sys/block"); i != directory_iterator(); ++i) { string const name = i->path().filename().string(); path device_type_file("/sys/block/" + name + "/device/type"); @@ -300,8 +311,8 @@ get_drives () model = dcp::file_to_string("/sys/block/" + name + "/device/model"); boost::trim(*model); } catch (...) {} - BOOST_FOREACH (string j, mounted_devices) { - if (boost::algorithm::starts_with(j, "/dev/" + name)) { + for (vector >::const_iterator j = mounted_devices.begin(); j != mounted_devices.end(); ++j) { + if (boost::algorithm::starts_with(j->first, "/dev/" + name)) { mounted = true; } } @@ -342,3 +353,18 @@ config_path () p /= "dcpomatic2"; return p; } + +bool +unmount_drive (string drive) +{ + vector > mounts = get_mounts (drive); + for (vector >::const_iterator i = mounts.begin(); i != mounts.end(); ++i) { + int const r = umount(i->second.c_str()); + LOG_DISK("Tried to unmount %1 and got %2 and %3", i->second, r, errno); + if (r == -1) { + return false; + } + } + return true; +} + diff --git a/src/lib/cross_osx.cc b/src/lib/cross_osx.cc index c52dfc434..a363f0570 100644 --- a/src/lib/cross_osx.cc +++ b/src/lib/cross_osx.cc @@ -485,3 +485,12 @@ config_path () p /= "2"; return p; } + +bool +unmount_device (string device) +{ + int const r = umount(device.c_str()); + LOG_DISK("Tried to unmount %1 and got %2 and %3", device, r, errno); + return r == 0; + +} diff --git a/src/lib/exceptions.cc b/src/lib/exceptions.cc index d394ad4b2..3991c57b9 100644 --- a/src/lib/exceptions.cc +++ b/src/lib/exceptions.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2020 Carl Hetherington This file is part of DCP-o-matic. @@ -25,6 +25,7 @@ using std::string; using std::runtime_error; +using boost::optional; /** @param f File that we were trying to open */ OpenFileError::OpenFileError (boost::filesystem::path f, int error, Mode mode) @@ -115,14 +116,20 @@ GLError::GLError (char const * last, int e) } -CopyError::CopyError (string m, int n) - : runtime_error (String::compose("%1 (%2)", m, n)) +CopyError::CopyError (string m, optional n) + : runtime_error (String::compose("%1%2", m, n ? String::compose(" (%1)", *n) : "")) , _message (m) , _number (n) { } +CommunicationFailedError::CommunicationFailedError () + : CopyError (_("Lost communication between main and writer processes")) +{ + +} + VerifyError::VerifyError (string m, int n) : runtime_error (String::compose("%1 (%2)", m, n)) , _message (m) diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index 0f8a2eda2..98534bb32 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -30,6 +30,7 @@ extern "C" { #include } #include +#include #include #include @@ -320,22 +321,33 @@ public: class CopyError : public std::runtime_error { public: - CopyError (std::string s, int n); + CopyError (std::string s, boost::optional n = boost::optional()); virtual ~CopyError () throw () {} std::string message () const { return _message; } - int number () const { + boost::optional number () const { return _number; } private: std::string _message; - int _number; + boost::optional _number; }; + +/** @class CommunicationFailedError + * @brief Communcation between dcpomatic2_disk and _disk_writer failed somehow. + */ +class CommunicationFailedError : public CopyError +{ +public: + CommunicationFailedError (); +}; + + /** @class VerifyError * @brief An error which occurs when verifying a DCP that we copied to a distribution drive. */ diff --git a/src/lib/nanomsg.cc b/src/lib/nanomsg.cc index 57220cd54..0fc0dd357 100644 --- a/src/lib/nanomsg.cc +++ b/src/lib/nanomsg.cc @@ -20,6 +20,7 @@ #include "nanomsg.h" #include "dcpomatic_log.h" +#include "exceptions.h" #include #include #include @@ -48,23 +49,16 @@ Nanomsg::Nanomsg (bool server) } } -void -Nanomsg::blocking_send (string s) +bool +Nanomsg::send (string s, int timeout) { - int const r = nn_send (_socket, s.c_str(), s.length(), 0); - if (r < 0) { - throw runtime_error(String::compose("Could not send to nanomsg socket (%1)", errno)); - } else if (r != int(s.length())) { - throw runtime_error("Could not send to nanomsg socket (message too big)"); + if (timeout != 0) { + nn_setsockopt (_socket, NN_SOL_SOCKET, NN_SNDTIMEO, &timeout, sizeof(int)); } -} -bool -Nanomsg::nonblocking_send (string s) -{ - int const r = nn_send (_socket, s.c_str(), s.length(), NN_DONTWAIT); + int const r = nn_send (_socket, s.c_str(), s.length(), timeout ? 0 : NN_DONTWAIT); if (r < 0) { - if (errno == EAGAIN) { + if (errno == ETIMEDOUT || errno == EAGAIN) { return false; } throw runtime_error(String::compose("Could not send to nanomsg socket (%1)", errno)); @@ -88,17 +82,17 @@ Nanomsg::get_from_pending () } void -Nanomsg::recv_and_parse (bool blocking) +Nanomsg::recv_and_parse (int flags) { char* buf = 0; - int const received = nn_recv (_socket, &buf, NN_MSG, blocking ? 0 : NN_DONTWAIT); + int const received = nn_recv (_socket, &buf, NN_MSG, flags); if (received < 0) { - if (!blocking && errno == EAGAIN) { + if (errno == ETIMEDOUT || errno == EAGAIN) { return; } - throw runtime_error ("Could not communicate with subprocess"); + throw CommunicationFailedError (); } char* p = buf; @@ -114,32 +108,24 @@ Nanomsg::recv_and_parse (bool blocking) nn_freemsg (buf); } -string -Nanomsg::blocking_get () +optional +Nanomsg::receive (int timeout) { + if (timeout != 0) { + nn_setsockopt (_socket, NN_SOL_SOCKET, NN_RCVTIMEO, &timeout, sizeof(int)); + } + optional l = get_from_pending (); if (l) { return *l; } - recv_and_parse (true); + recv_and_parse (timeout ? 0 : NN_DONTWAIT); - l = get_from_pending (); + return get_from_pending (); if (!l) { - throw runtime_error ("Could not communicate with subprocess"); + throw CommunicationFailedError (); } return *l; } - -optional -Nanomsg::nonblocking_get () -{ - optional l = get_from_pending (); - if (l) { - return *l; - } - - recv_and_parse (false); - return get_from_pending (); -} diff --git a/src/lib/nanomsg.h b/src/lib/nanomsg.h index dc84a6ce7..9bd87098b 100644 --- a/src/lib/nanomsg.h +++ b/src/lib/nanomsg.h @@ -28,18 +28,21 @@ class Nanomsg : public boost::noncopyable public: explicit Nanomsg (bool server); - void blocking_send (std::string s); - /** Try to send a message, returning true if successful, false - * if we should try again (EAGAIN) or throwing an exception on any other - * error. + /** Try to send a message, waiting for some timeout before giving up. + * @param timeout Timeout in milliseconds, or -1 for infinite timeout. + * @return true if the send happened, false if there was a timeout. */ - bool nonblocking_send (std::string s); - std::string blocking_get (); - boost::optional nonblocking_get (); + bool send (std::string s, int timeout); + + /** Try to receive a message, waiting for some timeout before giving up. + * @param timeout Timeout in milliseconds, or -1 for infinite timeout. + * @return Empty if the timeout was reached, otherwise the received string. + */ + boost::optional receive (int timeout); private: boost::optional get_from_pending (); - void recv_and_parse (bool blocking); + void recv_and_parse (int flags); int _socket; std::list _pending; diff --git a/src/tools/dcpomatic_disk.cc b/src/tools/dcpomatic_disk.cc index baccdbce3..6dbfbe4b0 100644 --- a/src/tools/dcpomatic_disk.cc +++ b/src/tools/dcpomatic_disk.cc @@ -22,6 +22,8 @@ #include "wx/wx_util.h" #include "wx/job_manager_view.h" #include "wx/drive_wipe_warning_dialog.h" +#include "wx/try_unmount_dialog.h" +#include "wx/message_dialog.h" #include "lib/file_log.h" #include "lib/dcpomatic_log.h" #include "lib/util.h" @@ -44,8 +46,8 @@ using std::string; using std::exception; using std::cout; using std::cerr; -using std::runtime_error; using boost::shared_ptr; +using boost::optional; class DOMFrame : public wxFrame { @@ -133,7 +135,7 @@ public: ~DOMFrame () { - _nanomsg.blocking_send(DISK_WRITER_QUIT "\n"); + _nanomsg.send(DISK_WRITER_QUIT "\n", 2000); } private: @@ -163,6 +165,34 @@ private: { DCPOMATIC_ASSERT (_drive->GetSelection() != wxNOT_FOUND); DCPOMATIC_ASSERT (static_cast(_dcp_path)); + + Drive const& drive = _drives[_drive->GetSelection()]; + if (drive.mounted()) { + TryUnmountDialog* d = new TryUnmountDialog(this, drive.description()); + int const r = d->ShowModal (); + d->Destroy (); + if (r == wxID_OK) { + if (!_nanomsg.send(DISK_WRITER_UNMOUNT "\n", 2000)) { + throw CommunicationFailedError (); + } + if (!_nanomsg.send(drive.internal_name() + "\n", 2000)) { + throw CommunicationFailedError (); + } + optional reply = _nanomsg.receive (2000); + if (!reply || *reply != DISK_WRITER_OK) { + MessageDialog* m = new MessageDialog ( + this, + _("DCP-o-matic Disk Writer"), + wxString::Format(_("The drive %s could not be unmounted.\nClose any application that is using it, then try again."), std_to_wx(drive.description())) + ); + m->ShowModal (); + m->Destroy (); + return; + } + } + } + + DriveWipeWarningDialog* d = new DriveWipeWarningDialog (this, _drive->GetString(_drive->GetSelection())); int const r = d->ShowModal (); bool ok = r == wxID_OK && d->confirmed(); @@ -186,12 +216,7 @@ private: _drive->Clear (); int re_select = wxNOT_FOUND; int j = 0; - _drives.clear (); - BOOST_FOREACH (Drive i, get_drives()) { - if (!i.mounted()) { - _drives.push_back (i); - } - } + _drives = get_drives (); BOOST_FOREACH (Drive i, _drives) { wxString const s = std_to_wx(i.description()); if (s == current) { diff --git a/src/tools/dcpomatic_disk_writer.cc b/src/tools/dcpomatic_disk_writer.cc index 9518ac555..5e76341eb 100644 --- a/src/tools/dcpomatic_disk_writer.cc +++ b/src/tools/dcpomatic_disk_writer.cc @@ -80,11 +80,12 @@ 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; +#define SHORT_TIMEOUT 100 +#define LONG_TIMEOUT 2000 + static void count (boost::filesystem::path dir, uint64_t& total_bytes) @@ -147,7 +148,7 @@ write (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total } remaining -= this_time; total_remaining -= this_time; - nanomsg->blocking_send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total))); + nanomsg->send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)), SHORT_TIMEOUT); } fclose (in); @@ -186,7 +187,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; - nanomsg->blocking_send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total))); + nanomsg->send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)), SHORT_TIMEOUT); } ext4_fclose (&in); @@ -229,9 +230,10 @@ copy (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total_ } } + static void -write () +write (boost::filesystem::path dcp_path, string device) try { // ext4_dmask_set (DEBUG_ALL); @@ -314,7 +316,7 @@ try } LOG_DISK_NC ("Opened partition"); - nanomsg->blocking_send(DISK_WRITER_FORMATTING "\n"); + nanomsg->send(DISK_WRITER_FORMATTING "\n", SHORT_TIMEOUT); r = ext4_mkfs(&fs, bd, &info, F_SET_EXT4); if (r != EOK) { @@ -349,27 +351,37 @@ try } ext4_device_unregister("ext4_fs"); - nanomsg->blocking_send(DISK_WRITER_OK "\n"); + if (!nanomsg->send(DISK_WRITER_OK "\n", LONG_TIMEOUT)) { + throw CommunicationFailedError (); + } } catch (CopyError& e) { - LOG_DISK("CopyError: %1 %2", e.message(), e.number()); - nanomsg->blocking_send(String::compose(DISK_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number())); + LOG_DISK("CopyError (from write): %1 %2", e.message(), e.number().get_value_or(0)); + nanomsg->send(String::compose(DISK_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number().get_value_or(0)), LONG_TIMEOUT); } catch (VerifyError& e) { - LOG_DISK("VerifyError: %1 %2", e.message(), e.number()); - nanomsg->blocking_send(String::compose(DISK_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number())); + LOG_DISK("VerifyError (from write): %1 %2", e.message(), e.number()); + nanomsg->send(String::compose(DISK_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number()), LONG_TIMEOUT); } catch (exception& e) { - LOG_DISK("Exception: %1", e.what()); - nanomsg->blocking_send(String::compose(DISK_WRITER_ERROR "\n%1\n0\n", e.what())); + LOG_DISK("Exception (from write): %1", e.what()); + nanomsg->send(String::compose(DISK_WRITER_ERROR "\n%1\n0\n", e.what()), LONG_TIMEOUT); } +struct Parameters +{ + boost::filesystem::path dcp_path; + std::string device; +}; + #ifdef DCPOMATIC_LINUX static void -polkit_callback (GObject *, GAsyncResult* res, gpointer) +polkit_callback (GObject *, GAsyncResult* res, gpointer data) { + Parameters* parameters = reinterpret_cast (data); PolkitAuthorizationResult* result = polkit_authority_check_authorization_finish (polkit_authority, res, 0); if (result && polkit_authorization_result_get_is_authorized(result)) { - write (); + write (parameters->dcp_path, parameters->device); } + delete parameters; if (result) { g_object_unref (result); } @@ -378,40 +390,59 @@ polkit_callback (GObject *, GAsyncResult* res, gpointer) bool idle () +try { using namespace boost::algorithm; - optional s = nanomsg->nonblocking_get (); + optional s = nanomsg->receive (0); if (!s) { return true; } if (*s == DISK_WRITER_QUIT) { exit (EXIT_SUCCESS); - } else if (*s == DISK_WRITER_WRITE) { - dcp_path = nanomsg->blocking_get(); - device = nanomsg->blocking_get(); + } else if (*s == DISK_WRITER_UNMOUNT) { + /* XXX: should do Linux polkit stuff here */ + optional device = nanomsg->receive (LONG_TIMEOUT); + if (!device) { + throw CommunicationFailedError (); + } + if (unmount_drive(*device)) { + if (!nanomsg->send (DISK_WRITER_OK "\n", LONG_TIMEOUT)) { + throw CommunicationFailedError(); + } + } else { + if (!nanomsg->send (DISK_WRITER_ERROR "\n", LONG_TIMEOUT)) { + throw CommunicationFailedError(); + } + } + } else { + optional dcp_path = nanomsg->receive(LONG_TIMEOUT); + optional device = nanomsg->receive(LONG_TIMEOUT); + if (!dcp_path || !device) { + throw CommunicationFailedError(); + } /* Do some basic sanity checks; this is a bit belt-and-braces but it can't hurt... */ #ifdef DCPOMATIC_OSX - if (!starts_with(device, "/dev/disk")) { - LOG_DISK ("Will not write to %1", device); - nanomsg->blocking_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n"); + if (!starts_with(*device, "/dev/disk")) { + LOG_DISK ("Will not write to %1", *device); + nanomsg->try_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } #endif #ifdef DCPOMATIC_LINUX - if (!starts_with(device, "/dev/sd") && !starts_with(device, "/dev/hd")) { - LOG_DISK ("Will not write to %1", device); - nanomsg->blocking_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n"); + if (!starts_with(*device, "/dev/sd") && !starts_with(*device, "/dev/hd")) { + LOG_DISK ("Will not write to %1", *device); + nanomsg->send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } #endif #ifdef DCPOMATIC_WINDOWS - if (!starts_with(device, "\\\\.\\PHYSICALDRIVE")) { - LOG_DISK ("Will not write to %1", device); - nanomsg->blocking_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n"); + if (!starts_with(*device, "\\\\.\\PHYSICALDRIVE")) { + LOG_DISK ("Will not write to %1", *device); + nanomsg->try_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } #endif @@ -419,36 +450,42 @@ idle () bool on_drive_list = false; bool mounted = false; for (auto const& i: get_drives()) { - if (i.internal_name() == device) { + if (i.internal_name() == *device) { on_drive_list = true; mounted = i.mounted(); } } if (!on_drive_list) { - LOG_DISK ("Will not write to %1 as it's not recognised as a drive", device); - nanomsg->blocking_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n"); + LOG_DISK ("Will not write to %1 as it's not recognised as a drive", *device); + nanomsg->send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } if (mounted) { - LOG_DISK ("Will not write to %1 as it's mounted", device); - nanomsg->blocking_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n"); + LOG_DISK ("Will not write to %1 as it's mounted", *device); + nanomsg->send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } - LOG_DISK ("Here we go writing %1 to %2", dcp_path, device); + LOG_DISK ("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()); + Parameters* parameters = new Parameters; + parameters->dcp_path = *dcp_path; + parameters->device = *device; polkit_authority_check_authorization ( - polkit_authority, subject, "com.dcpomatic.write-drive", 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, 0, polkit_callback, 0 + polkit_authority, subject, "com.dcpomatic.write-drive", 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, 0, polkit_callback, parameters ); #else - write (); + write (*dcp_path, *device); #endif } + return true; +} catch (exception& e) { + LOG_DISK("Exception (from idle): %1", e.what()); return true; } diff --git a/src/wx/try_unmount_dialog.cc b/src/wx/try_unmount_dialog.cc new file mode 100644 index 000000000..d25ae8c3e --- /dev/null +++ b/src/wx/try_unmount_dialog.cc @@ -0,0 +1,42 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + +#include "try_unmount_dialog.h" +#include "wx_util.h" +#include "static_text.h" +#include + +TryUnmountDialog::TryUnmountDialog (wxWindow* parent, wxString description) + : wxDialog (parent, wxID_ANY, _("DCP-o-matic Disk Writer")) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + wxStaticText* text = new StaticText (this, wxString::Format(_("The drive %s is mounted.\nIt must be unmounted before DCP-o-matic can write to it. Do you want to try to unmount it now?"), description)); + sizer->Add (text, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + sizer->Add(buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (sizer); + sizer->Layout (); + sizer->SetSizeHints (this); +} + diff --git a/src/wx/try_unmount_dialog.h b/src/wx/try_unmount_dialog.h new file mode 100644 index 000000000..9ae7de933 --- /dev/null +++ b/src/wx/try_unmount_dialog.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + +#include + +class TryUnmountDialog : public wxDialog +{ +public: + TryUnmountDialog (wxWindow* parent, wxString description); +}; diff --git a/src/wx/wscript b/src/wx/wscript index 87ae38aac..6a9003ef1 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -147,6 +147,7 @@ sources = """ timeline_video_content_view.cc timeline_view.cc timing_panel.cc + try_unmount_dialog.cc update_dialog.cc verify_dcp_dialog.cc video_panel.cc -- 2.30.2