-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlaunchctl-kick
executable file
·161 lines (147 loc) · 3.35 KB
/
launchctl-kick
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env bash
#
# Synopsis:
# Simple frontend for OSX launchctl to stop/unload/load/list services.
# Usage:
# sudo -i
# launchctl-kick jmsdesk.blobio.*
#
# alias kickjms=launchctl-kick jmsdesk.blobio.*
# Note:
# Consider refactoring to call scripts launchctl-{load,unload}
#
# is "stop" done by "unload"?
#
# the action "kickstart" seems like what we should do instead of this
# script. however, "kickstart" requires a "service-target", which seems
# to need meta info, like user or session 9acording to the manual).
# perhaps we can construct a "service-target" by querying the
# *.plist file for, say, user id. not sure.
#
LD=/Library/LaunchDaemons
LOAD_PAUSE_DURATION=3
log()
{
echo "$@"
}
die()
{
log "ERROR: $@" >&2
exit 1
}
WARN()
{
log "WARN (ok): $@" >&2
}
#
# Extract a value from plist, cause the path syntax for extract lacks
# documentation
#
get_plist_value()
{
plutil -p $PLIST |
fgrep "\"$1\"" |
awk '{print $3}' |
sed 's/"//g'
}
test $(pwd) = $LD && die "can not run in services dir: $D"
test $# = 1 || die "wrong argument count: got $#, expected 1"
cd $LD || die "cd $LD failed: exit status=$?"
for PLIST in $@; do
test -r $PLIST || die "can not read plist file: $PLIST"
if [[ "$PLIST" =~ ^.*\.plist$ ]]; then
SRV=$(basename $PLIST .plist)
else
die "service file must match *.plist: $PLIST"
fi
log "stopping $SRV"
launchctl stop $SRV
STATUS=$?
case $STATUS in
0)
log "service stopped: $SRV"
;;
3)
WARN 'process already stopped'
;;
*)
EMSG=$(launchctl error $STATUS)
die "launchctl stop failed: exit status: $EMSG"
;;
esac
log "unloading plist: $PLIST"
E=$(launchctl unload $PLIST 2>&1 | tail -1)
STATUS=$?
case $STATUS in
0)
#
# launchctl returns 0 when service already unloaded.
# also writes
#
# Unload failed: 113: Could not find specified service
#
# to standard error, so grep for that pattern.
#
# the pain never ends.
#
if [[ "$(echo $E | tail -1)" =~ ^.*:[[:space:]]113:.*$ ]]; then
WARN 'process not loaded'
elif [ -n "$EMSG" ]; then
die "launchctl: unexpected stderr: $EMSG"
fi
log "plist unloaded: $PLIST"
;;
*)
EMSG=$(launchctl error $STATUS)
die "launchctl stop failed: exit status: $EMSG"
;;
esac
DISABLED=$(get_plist_value Disabled)
if [ "$DISABLED" = 1 ]; then
log "service disabled: $SRV"
continue
fi
log "loading plist: $PLIST"
launchctl load $PLIST
STATUS=$?
case $STATUS in
0)
;;
*)
EMSG=$(launchctl error $STATUS)
die "launchctl load failed: exit status: $EMSG"
;;
esac
log "service loaded: $SRV"
log "sleep $LOAD_PAUSE_DURATION sec before kick start"
sleep $LOAD_PAUSE_DURATION
log "plist loaded: $PLIST"
log "list service: $SRV"
SRV_PID=$(
launchctl list $SRV |
fgrep '"PID" = ' |
awk '{print $3}' |
sed 's/[^0-9]//g'
)
if [ -n "$SRV_PID" ]; then
log "pid of service process: $SRV_PID"
else
test -z "$SRV_PID" && WARN "can not get pid: $SRV"
WARN "service failed to start: $SRV"
STDERR=$(get_plist_value StandardErrorPath)
if [ -n "$STDERR" ]; then
log "stderr of service: $STDERR"
cat <<END
$(basename $STDERR) ----------------------------------------------------------
END
tput smso
tail $STDERR
tput rmso
cat <<END
$(basename $STDERR) ----------------------------------------------------------
END
else
WARN "no key <StandardErrorPath>: $PLIST"
fi
fi
done