1"""
2The service module for Slackware
3
4.. important::
5    If you feel that Salt should be using this module to manage services on a
6    minion, and it is using a different module (or gives an error similar to
7    *'service.start' is not available*), see :ref:`here
8    <module-provider-override>`.
9"""
10
11import fnmatch
12import glob
13import os
14import re
15
16__func_alias__ = {"reload_": "reload"}
17
18# Define the module's virtual name
19__virtualname__ = "service"
20
21prefix = "/etc/rc.d/rc"
22
23
24def __virtual__():
25    """
26    Only work on Slackware
27    """
28    if __grains__["os"] == "Slackware":
29        return __virtualname__
30    return (
31        False,
32        "The slackware_service execution module failed to load: only available on"
33        " Slackware.",
34    )
35
36
37def start(name):
38    """
39    Start the specified service
40
41    .. versionadded:: 3002
42
43    CLI Example:
44
45    .. code-block:: bash
46
47        salt '*' service.start <service name>
48    """
49    cmd = "/bin/sh {}.{} start".format(prefix, name)
50    return not __salt__["cmd.retcode"](cmd)
51
52
53def stop(name):
54    """
55    Stop the specified service
56
57    .. versionadded:: 3002
58
59    CLI Example:
60
61    .. code-block:: bash
62
63        salt '*' service.stop <service name>
64    """
65    cmd = "/bin/sh {}.{} stop".format(prefix, name)
66    return not __salt__["cmd.retcode"](cmd)
67
68
69def restart(name):
70    """
71    Restart the named service
72
73    .. versionadded:: 3002
74
75    CLI Example:
76
77    .. code-block:: bash
78
79        salt '*' service.restart <service name>
80    """
81    cmd = "/bin/sh {}.{} restart".format(prefix, name)
82    return not __salt__["cmd.retcode"](cmd)
83
84
85def reload_(name):
86    """
87    Reload the named service
88
89    .. versionadded:: 3002
90
91    CLI Example:
92
93    .. code-block:: bash
94
95        salt '*' service.reload <service name>
96    """
97    cmd = "/bin/sh {}.{} reload".format(prefix, name)
98    return not __salt__["cmd.retcode"](cmd)
99
100
101def force_reload(name):
102    """
103    Force-reload the named service
104
105    .. versionadded:: 3002
106
107    CLI Example:
108
109    .. code-block:: bash
110
111        salt '*' service.force_reload <service name>
112    """
113    cmd = "/bin/sh {}.{} forcereload".format(prefix, name)
114    return not __salt__["cmd.retcode"](cmd)
115
116
117def status(name, sig=None):
118    """
119    Return the status for a service.
120    If the name contains globbing, a dict mapping service name to True/False
121    values is returned.
122
123    .. versionadded:: 3002
124
125    Args:
126        name (str): The name of the service to check
127        sig (str): Signature to use to find the service via ps
128
129    Returns:
130        bool: True if running, False otherwise
131        dict: Maps service name to True if running, False otherwise
132
133    CLI Example:
134
135    .. code-block:: bash
136
137        salt '*' service.status <service name> [service signature]
138    """
139    if sig:
140        return bool(__salt__["status.pid"](sig))
141
142    contains_globbing = bool(re.search(r"\*|\?|\[.+\]", name))
143    if contains_globbing:
144        services = fnmatch.filter(get_all(), name)
145    else:
146        services = [name]
147    results = {}
148    for service in services:
149        cmd = "/bin/sh {}.{} status".format(prefix, service)
150        results[service] = not __salt__["cmd.retcode"](cmd, ignore_retcode=True)
151    if contains_globbing:
152        return results
153    return results[name]
154
155
156def _get_svc(rcd, service_status):
157    """
158    Returns a unique service status
159    """
160    if os.path.exists(rcd):
161        ena = os.access(rcd, os.X_OK)
162        svc = rcd.split(".")[2]
163        if service_status == "":
164            return svc
165        elif service_status == "ON" and ena:
166            return svc
167        elif service_status == "OFF" and (not ena):
168            return svc
169    return None
170
171
172def _get_svc_list(service_status):
173    """
174    Returns all service statuses
175    """
176    notservice = re.compile(
177        r"{}.([A-Za-z0-9_-]+\.conf|0|4|6|K|M|S|inet1|inet2|local|modules.*|wireless)$".format(
178            prefix
179        )
180    )
181    ret = set()
182    lines = glob.glob("{}.*".format(prefix))
183    for line in lines:
184        if not notservice.match(line):
185            svc = _get_svc(line, service_status)
186            if svc is not None:
187                ret.add(svc)
188
189    return sorted(ret)
190
191
192def get_enabled():
193    """
194    Return a list of service that are enabled on boot
195
196    .. versionadded:: 3002
197
198    CLI Example:
199
200    .. code-block:: bash
201
202        salt '*' service.get_enabled
203    """
204    return _get_svc_list("ON")
205
206
207def get_disabled():
208    """
209    Return a set of services that are installed but disabled
210
211    .. versionadded:: 3002
212
213    CLI Example:
214
215    .. code-block:: bash
216
217        salt '*' service.get_disabled
218    """
219    return _get_svc_list("OFF")
220
221
222def available(name):
223    """
224    Returns ``True`` if the specified service is available, otherwise returns
225    ``False``.
226
227    .. versionadded:: 3002
228
229    CLI Example:
230
231    .. code-block:: bash
232
233        salt '*' service.available sshd
234    """
235    return name in get_all()
236
237
238def missing(name):
239    """
240    The inverse of service.available.
241    Returns ``True`` if the specified service is not available, otherwise returns
242    ``False``.
243
244    .. versionadded:: 3002
245
246    CLI Example:
247
248    .. code-block:: bash
249
250        salt '*' service.missing sshd
251    """
252    return name not in get_all()
253
254
255def get_all():
256    """
257    Return all available boot services
258
259    .. versionadded:: 3002
260
261    CLI Example:
262
263    .. code-block:: bash
264
265        salt '*' service.get_all
266    """
267    return _get_svc_list("")
268
269
270def _rcd_mode(name, ena):
271    """
272    Enable/Disable a service
273    """
274    rcd = prefix + "." + name
275    if os.path.exists(rcd):
276        perms = os.stat(rcd).st_mode
277        if ena == "ON":
278            perms |= 0o111
279            os.chmod(rcd, perms)
280        elif ena == "OFF":
281            perms &= 0o777666
282            os.chmod(rcd, perms)
283        return True
284
285    return False
286
287
288def enable(name, **kwargs):
289    """
290    Enable the named service to start at boot
291
292    .. versionadded:: 3002
293
294    CLI Example:
295
296    .. code-block:: bash
297
298        salt '*' service.enable <service name>
299    """
300    return _rcd_mode(name, "ON")
301
302
303def disable(name, **kwargs):
304    """
305    Disable the named service to start at boot
306
307    .. versionadded:: 3002
308
309    CLI Example:
310
311    .. code-block:: bash
312
313        salt '*' service.disable <service name>
314    """
315    return _rcd_mode(name, "OFF")
316
317
318def enabled(name, **kwargs):
319    """
320    Return True if the named service is enabled, false otherwise
321
322    .. versionadded:: 3002
323
324    CLI Example:
325
326    .. code-block:: bash
327
328        salt '*' service.enabled <service name>
329    """
330    ret = True
331    if _get_svc("{}.{}".format(prefix, name), "ON") is None:
332        ret = False
333    return ret
334
335
336def disabled(name):
337    """
338    Return True if the named service is enabled, false otherwise
339
340    .. versionadded:: 3002
341
342    CLI Example:
343
344    .. code-block:: bash
345
346        salt '*' service.disabled <service name>
347    """
348    ret = True
349    if _get_svc("{}.{}".format(prefix, name), "OFF") is None:
350        ret = False
351    return ret
352
353
354# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
355