1600
launchctl_remove_plist(SCHEDULE_WEEKLY, cmd);
1601
}
1602
1603
+static int launchctl_list_contains_plist(const char *name, const char *cmd)
1604
+{
1605
+ int result;
1606
+ struct child_process child = CHILD_PROCESS_INIT;
1607
+ char *uid = launchctl_get_uid();
1608
+
1609
+ strvec_split(&child.args, cmd);
1610
+ strvec_pushl(&child.args, "list", name, NULL);
1611
+
1612
+ child.no_stderr = 1;
1613
+ child.no_stdout = 1;
1614
+
1615
+ if (start_command(&child))
1616
+ die(_("failed to start launchctl"));
1617
+
1618
+ result = finish_command(&child);
1619
+
1620
+ free(uid);
1621
+
1622
+ /* Returns failure if 'name' doesn't exist. */
1623
+ return !result;
1624
+}
1625
+
1626
static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule, const char *cmd)
1627
{
1628
int i, fd;
1632
char *filename = launchctl_service_filename(name);
1633
struct lock_file lk = LOCK_INIT;
1634
static unsigned long lock_file_timeout_ms = ULONG_MAX;
1612
- struct strbuf plist = STRBUF_INIT;
1635
+ struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
1636
+ struct stat st;
1637
1638
preamble = "<?xml version=\"1.0\"?>\n"
1639
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
1700
fd = hold_lock_file_for_update_timeout(&lk, filename, LOCK_DIE_ON_ERROR,
1701
lock_file_timeout_ms);
1702
1679
- if (write_in_full(fd, plist.buf, plist.len) < 0 ||
1680
- commit_lock_file(&lk))
1681
- die_errno(_("could not write '%s'"), filename);
1682
-
1683
- /* bootout might fail if not already running, so ignore */
1684
- launchctl_boot_plist(0, filename, cmd);
1685
- if (launchctl_boot_plist(1, filename, cmd))
1686
- die(_("failed to bootstrap service %s"), filename);
1703
+ /*
1704
+ * Does this file already exist? With the intended contents? Is it
1705
+ * registered already? Then it does not need to be re-registered.
1706
+ */
1707
+ if (!stat(filename, &st) && st.st_size == plist.len &&
1708
+ strbuf_read_file(&plist2, filename, plist.len) == plist.len &&
1709
+ !strbuf_cmp(&plist, &plist2) &&
1710
+ launchctl_list_contains_plist(name, cmd))
1711
+ rollback_lock_file(&lk);
1712
+ else {
1713
+ if (write_in_full(fd, plist.buf, plist.len) < 0 ||
1714
+ commit_lock_file(&lk))
1715
+ die_errno(_("could not write '%s'"), filename);
1716
+
1717
+ /* bootout might fail if not already running, so ignore */
1718
+ launchctl_boot_plist(0, filename, cmd);
1719
+ if (launchctl_boot_plist(1, filename, cmd))
1720
+ die(_("failed to bootstrap service %s"), filename);
1721
+ }
1722
1723
free(filename);
1724
free(name);
1725
strbuf_release(&plist);
1726
+ strbuf_release(&plist2);
1727
return 0;
1728
}
1729