launchr 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/extconf.rb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+ create_makefile("launchd-socket-listener-unload")
5
+
6
+ makefile = File.read("Makefile")
7
+ makefile.gsub!(/-bundle ?/,"")
8
+ makefile.gsub!(/\$\(TARGET\)\.bundle/,"$(TARGET)")
9
+
10
+ File.open("Makefile","w") do |f|
11
+ f.puts makefile
12
+ end
13
+
14
+
@@ -0,0 +1,160 @@
1
+ //
2
+ // launchd-socket-listener-unload.cpp
3
+ // http://fazekasmiklos.blogspot.com/2007/04/howto-unload-launchd-deamon-from-itself.html
4
+ //
5
+ // Instructions by Dreamcat4 (dreamcat4@gmail.com)
6
+ //
7
+ // To compile:
8
+ // $ g++ launchd-socket-listener-unload.cpp -o launchd-socket-listener-unload
9
+ //
10
+ // A small program which unloads the launchd job that started it
11
+ // Use with the below configuration to trigger the real job to load
12
+ //
13
+ // Create a plist file for this daemon called "launchd.myjob.label-loader.plist"
14
+ // Put the listener socket definitions here
15
+ //
16
+ //
17
+ // <key>Program</key>
18
+ // <string>/path/to/launchd-socket-listener-unload</string>
19
+ // <key>ServiceIPC</key>
20
+ // <true/>
21
+ // <key>Sockets</key>
22
+ // <dict>
23
+ // <key>Listeners</key>
24
+ // <dict>
25
+ // <!-- Service name (/etc/services), or a tcp port number -->
26
+ // <!-- or can be anything else launchd supports (udp,etc) -->
27
+ // <key>SockServiceName</key>
28
+ // <string>8080</string>
29
+ // </dict>
30
+ // </dict>
31
+ //
32
+ // You probably already have made a 2nd plist file called "launchd_myjob_label.plist"
33
+ // Add to this file a KeepAlive directive, which depends on the first job not running
34
+ //
35
+ // keep alive -> other job enabled -> false
36
+ //
37
+ // <key>KeepAlive</key>
38
+ // <dict>
39
+ // <key>OtherJobEnabled</key>
40
+ // <dict>
41
+ // <key>launchd.myjob.label-loader</key>
42
+ // <false/>
43
+ // </dict>
44
+ // </dict>
45
+ //
46
+ //
47
+ // This job will then start when the first job is unloaded, which is
48
+ // whenever the first job is triggered by one of the listener sockets
49
+ //
50
+ // Bear in mind,
51
+ // The very first http request / connection attempt will be dropped
52
+ // So a connecting client will have to try again in order to establish
53
+ // a connection to the real job.
54
+
55
+ #include <stdlib.h>
56
+ #include <errno.h>
57
+ #include <syslog.h>
58
+
59
+ #include "launch.h"
60
+
61
+ class LaunchD
62
+ {
63
+ public:
64
+ LaunchD()
65
+ {
66
+ startedWithLaunchD = false;
67
+ me = 0;
68
+ CheckIn();
69
+ }
70
+
71
+ ~LaunchD()
72
+ {
73
+ if (me) {
74
+ launch_data_free(me);
75
+ }
76
+ }
77
+
78
+ bool CheckIn(bool allowRunWithoutLaunchd = true)
79
+ {
80
+ launch_data_t msg, resp;
81
+ msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
82
+ if ((resp = launch_msg(msg)) == NULL) {
83
+ if (allowRunWithoutLaunchd) {
84
+ startedWithLaunchD = false;
85
+ return false;
86
+ }
87
+ syslog(LOG_ERR,"Checkin with launchd failed: %m");
88
+ exit(EXIT_FAILURE);
89
+ }
90
+ launch_data_free(msg);
91
+ if (LAUNCH_DATA_ERRNO == launch_data_get_type(resp)) {
92
+ errno = launch_data_get_errno(resp);
93
+ if (errno == EACCES) {
94
+ syslog(LOG_ERR, "Check-in failed. Did you forget to set"
95
+ "ServiceIPC == true in your plist?");
96
+ } else {
97
+ syslog(LOG_ERR, "Check-in failed: %m");
98
+ }
99
+ exit(EXIT_FAILURE);
100
+ }
101
+ launch_data_t tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_LABEL);
102
+ me = launch_data_copy(tmp);
103
+ if(me)
104
+ {
105
+ syslog(LOG_ERR, "%s triggered\n",job_label());
106
+ }
107
+ startedWithLaunchD = true;
108
+ return true;
109
+ }
110
+
111
+ const char* job_label()
112
+ {
113
+ return launch_data_get_string(me);
114
+ }
115
+
116
+ bool Stop()
117
+ {
118
+ if (startedWithLaunchD) {
119
+ launch_data_t resp;
120
+ launch_data_t msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
121
+ if (! launch_data_dict_insert(msg,me,LAUNCH_KEY_REMOVEJOB)) {
122
+ syslog(LOG_ERR, "launch_data_dict_insert failed!\n");
123
+ return false;
124
+ }
125
+ if (! launch_data_dict_insert(msg,me,LAUNCH_KEY_STOPJOB)) {
126
+ syslog(LOG_ERR, "launch_data_dict_insert failed!\n");
127
+ return false;
128
+ }
129
+ syslog(LOG_ERR, "%s unloaded\n", job_label());
130
+ resp = launch_msg(msg);
131
+ syslog(LOG_ERR, "%s ...not unloaded. Failure when trying to unload %s.\n", job_label(), job_label());
132
+ if (resp == NULL) {
133
+ syslog(LOG_ERR, "launch_msg() LAUNCH_KEY_STOPJOB failed!\n");
134
+ return false;
135
+ }
136
+ if (LAUNCH_DATA_ERRNO == launch_data_get_type(resp)) {
137
+ errno = launch_data_get_errno(resp);
138
+ if (errno == EACCES) {
139
+ syslog(LOG_ERR, "Stop request failed EACCESS!");
140
+ } else {
141
+ syslog(LOG_ERR, "Check-in failed: %m");
142
+ }
143
+ exit(EXIT_FAILURE);
144
+ }
145
+ launch_data_free(msg);
146
+ }
147
+ return true;
148
+ }
149
+ private:
150
+ bool startedWithLaunchD;
151
+ launch_data_t me;
152
+ };
153
+
154
+
155
+ int main()
156
+ {
157
+ LaunchD ld;
158
+ ld.Stop();
159
+ }
160
+
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,14 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:runtime, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
+ require 'launchr'
12
+
13
+ require 'spec/expectations'
14
+
data/lib/launchr.rb ADDED
@@ -0,0 +1,105 @@
1
+
2
+ dir = File.dirname(__FILE__)
3
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
4
+
5
+ require 'launchr/path'
6
+
7
+ module Launchr
8
+ class << self
9
+ def config
10
+ @config ||= {}
11
+ end
12
+
13
+ def load_default
14
+ if Launchr::Path.launchr_default_boot.exist?
15
+ config[:boot] = true
16
+ else
17
+ config[:boot] = nil
18
+ end
19
+ end
20
+
21
+ def import_args
22
+ if config[:args][:user]
23
+ config[:boot] = nil
24
+
25
+ elsif config[:args][:boot]
26
+ config[:boot] = true
27
+ end
28
+ end
29
+
30
+ def label
31
+ # "com.github.homebrew.launchr"
32
+ "com.github.launchr"
33
+ end
34
+
35
+ def launchctl_timeout
36
+ 5
37
+ end
38
+
39
+ def real_user
40
+ Etc.getpwuid(Process.uid).name
41
+ end
42
+
43
+ def real_group
44
+ Etc.getgrgid(Process.gid).name
45
+ end
46
+
47
+ def superuser?
48
+ real_user == "root"
49
+ end
50
+
51
+ def sudo_user
52
+ if ENV["SUDO_USER"]
53
+ ENV["SUDO_USER"]
54
+ elsif ENV["SUDO_UID"]
55
+ Etc.getpwuid(ENV["SUDO_UID"].to_i).name
56
+ else
57
+ nil
58
+ end
59
+ end
60
+
61
+ def sudo_group
62
+ if ENV["SUDO_GROUP"]
63
+ ENV["SUDO_GROUP"]
64
+ elsif ENV["SUDO_GID"]
65
+ Etc.getgrgid(ENV["SUDO_GID"].to_i).name
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ def user
72
+ if superuser?
73
+ sudo_user || real_user
74
+ else
75
+ real_user
76
+ end
77
+ end
78
+
79
+ def group
80
+ if superuser?
81
+ sudo_group || real_group
82
+ else
83
+ real_group
84
+ end
85
+ end
86
+
87
+ def uid
88
+ Etc.getpwnam(user).uid
89
+ end
90
+
91
+ def gid
92
+ Etc.getgrnam(group).gid
93
+ end
94
+
95
+ def version
96
+ if Launchr::Path.launchr_version.exist?
97
+ Launchr::Path.launchr_version.read.strip
98
+ else
99
+ "0.0.0"
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+
@@ -0,0 +1,24 @@
1
+
2
+ require 'launchr/cli'
3
+ require 'launchr/commands'
4
+
5
+ module Launchr
6
+ # The Launchr Application Object. Instantiated for command-line mode
7
+ # @see Launchr::CLI
8
+ class Application
9
+
10
+ def initialize *args, &blk
11
+ @cli = Launchr::CLI.new
12
+
13
+ Launchr.load_default
14
+
15
+ Launchr.config[:args] = @cli.parse
16
+ Launchr.import_args
17
+
18
+ @commands = Launchr::Commands.new
19
+ @commands.run
20
+ end
21
+ end
22
+ end
23
+
24
+
@@ -0,0 +1,142 @@
1
+
2
+ require 'launchr/mixin/mixlib_cli'
3
+
4
+ module Launchr
5
+ # Defines options for the +launchr+ command line utility
6
+ class CLI
7
+ include Launchr::Mixlib::CLI
8
+
9
+ # The Launchr CLI Options
10
+ def self.launchr_cli_options
11
+
12
+ spaced_summary true
13
+ # banner false
14
+ summary_indent ""
15
+ summary_width 29
16
+
17
+ header "brew launchd - an extension to start and stop Launchd services."
18
+ header " `man brew-launchd` for more information"
19
+ header ""
20
+ banner "Usage: brew launchd [options]"
21
+
22
+ argument :start,
23
+ :long => "start service,(s)",
24
+ :type => Array,
25
+ :description => ["Start launchd service(s)",
26
+ "Equivalent to launchctl load -w files..."],
27
+ :example => "start dnsmasq memcached couchdb",
28
+ :default => nil
29
+
30
+ argument :stop,
31
+ :long => "stop service,(s)",
32
+ :type => Array,
33
+ :description => ["Stop launchd service(s)",
34
+ "Equivalent to launchctl unload -w files..."],
35
+ :example => "stop mamcached dnsmasq",
36
+ :default => nil
37
+
38
+ argument :restart,
39
+ :long => "restart service,(s)",
40
+ :type => Array,
41
+ :description => ["Restart launchd service(s)"],
42
+ :example => "restart couchdb",
43
+ :default => nil
44
+
45
+ option :user,
46
+ :indent => true,
47
+ :long => "--user",
48
+ :description => ["At user login.",
49
+ "Otherwise, the default setting will be used."],
50
+ :example => "start --user openvpn ddclient",
51
+ :requires => Proc.new { |args| (args[:boot] ^ args[:user]) && true || raise("--boot|--user") },
52
+ :default => nil
53
+
54
+ option :boot,
55
+ :indent => true,
56
+ :long => "--boot",
57
+ :description => ["At boot time. Requires sudo/root privelidges.",
58
+ "Otherwise, the default setting will be used."],
59
+ :example => "sudo brew start --boot nginx mysql",
60
+ :requires => Proc.new { |args| (args[:boot] ^ args[:user]) && true || raise("--boot|--user") },
61
+ :default => nil
62
+
63
+
64
+ argument :info,
65
+ :long => "info [service,(s)]",
66
+ :type => Array,
67
+ :proc => Proc.new { |l| (l == true) ? [] : l },
68
+ :description => ["Info for launchd service(s)","With no arguments prints info for all services."],
69
+ :example => "brew launchd info",
70
+ :default => nil
71
+
72
+ argument :clean,
73
+ :long => "clean",
74
+ :description => ["Clean missing/broken launchd service(s)."],
75
+ :example => ["brew launchd clean", "sudo brew launchd clean"],
76
+ :default => nil
77
+
78
+ argument :default,
79
+ :long => "default [--user|--boot]",
80
+ :description => [
81
+ "Set the default target to start launchd services.",
82
+ "The initial setting, --user will start daemons at",
83
+ "user login - from the Loginwindow (not over ssh).",
84
+ " ",
85
+ "Wheras --boot will set services to start at boot",
86
+ "time. But be aware that brew should be installed",
87
+ "to the root filesystem, not on a mounted volume."],
88
+
89
+ :example => [
90
+ "brew launchd default --boot",
91
+ "brew launchd default --user"
92
+ ],
93
+ :requires => Proc.new { |args| (args[:boot] ^ args[:user]) && true || raise("--boot|--user") },
94
+ :default => nil
95
+
96
+ option :help,
97
+ :long => "--help",
98
+ :description => "Show this message",
99
+ :show_options => true,
100
+ :exit => 0
101
+
102
+ option :version,
103
+ :long => "--version",
104
+ :description => "Print version information",
105
+ :default => nil
106
+ end
107
+ launchr_cli_options
108
+
109
+ def parse argv=ARGV
110
+ parse_options(argv)
111
+
112
+ [:start,:stop,:restart].each do |cmd|
113
+ case config[cmd]
114
+ when Array
115
+ [:user, :boot].each do |level|
116
+ if config[cmd].include? "--#{level}"
117
+ config[level] = true
118
+ end
119
+ end
120
+ config[cmd] -= ["--user","--boot"]
121
+ end
122
+ end
123
+
124
+ raise "Please choose one of --user|--boot" if config[:user] && config[:boot]
125
+
126
+ unless filtered_argv.empty?
127
+ start_stop_restart_value = [config[:start],config[:stop],config[:restart],config[:info]].compact!
128
+
129
+ if start_stop_restart_value.size == 1
130
+ services = *start_stop_restart_value
131
+ extra_services = filtered_argv
132
+
133
+ services << extra_services
134
+ services.flatten!
135
+ end
136
+ end
137
+
138
+ config
139
+ end
140
+
141
+ end
142
+ end