netctl.in 5.65 KB
Newer Older
1
#! /bin/bash
James Rayner's avatar
James Rayner committed
2

3
. /usr/lib/netctl/globals
James Rayner's avatar
James Rayner committed
4
5


6
usage() {
7
    cat << END
8
9
10
11
Usage: netctl {COMMAND} [PROFILE]
              [--help|--version]

Commands:
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  list                   List available profiles
  store                  Save which profiles are active
  restore                Load saved profiles
  stop-all               Stops all profiles
  start [PROFILE]        Start a profile
  stop [PROFILE]         Stop a profile
  restart [PROFILE]      Restart a profile
  switch-to [PROFILE]    Switch to a profile
  is-active [PROFILE]    Check whether a profile is active
  status [PROFILE]       Show runtime status of a profile
  enable [PROFILE]       Enable the systemd unit for a profile
  disable [PROFILE]      Disable the systemd unit for a profile
  reenable [PROFILE]     Reenable the systemd unit for a profile
  is-enabled [PROFILE]   Check whether a profile is enabled
26
27
  edit [PROFILE]         Edit a profile file
  verify [PROFILE]       Check the syntax of a profile file
28
  wait-online [PROFILE]  Wait for a profile to finish connecting
29
END
James Rayner's avatar
James Rayner committed
30
31
}

32
list() {
33
    local indicators=( ' ' '+' '*' ) i
34
    list_profiles | while IFS= read -r Profile; do
35
36
37
38
39
40
41
        if sd_call "is-active --quiet" "$Profile" &> /dev/null; then
            [[ $(sd_status_text "$Profile") == "online" ]]
            (( i = 2 - $? ))
        else
            (( i = 0 ))
        fi
        printf '%s %s\n' "${indicators[i]}" "$Profile"
42
43
44
45
    done
}

store() {
46
    mkdir -p "$(dirname "$STATE_FILE")"
47
    list_profiles | while IFS= read -r Profile; do
48
        if sd_call "is-active --quiet" "$Profile" &> /dev/null; then
49
            printf '%s\n' "$Profile"
50
51
        fi
    done > "$STATE_FILE"
52
53
54
55
56
}

restore() {
    if [[ ! -r $STATE_FILE ]]; then
        exit_error "Could not read state file '$STATE_FILE'"
57
58
59
    elif [[ ! -s $STATE_FILE ]]; then
        report_debug "No profiles to restore in state file '$STATE_FILE'"
    else
60
61
        mapfile -t Profiles < "$STATE_FILE"
        do_debug sd_call start "${Profiles[@]}"
62
63
64
65
66
67
    fi
}

stop_all() {
    # We cannot pipe to mapfile, as the end of a pipe is inside a subshell
    mapfile -t Profiles < <(list_profiles)
68
    if (( ${#Profiles[@]} )); then
69
        do_debug sd_call stop "${Profiles[@]}" 2> >(grep -Fv 'not loaded' >&2)
70
    fi
71
72
73
74
75
76
77
}

switch_to() {
    cd "$PROFILE_DIR"
    # We assume interface names are not quoted
    # Using read removes leading whitespace
    read InterfaceLine < \
78
      <(grep -om1 '^[[:space:]]*Interface=[[:alnum:]:._-]\+' "$1")
79
80
81
82
83
    if [[ -z $InterfaceLine ]]; then
        exit_error "Profile '$1' does not specify an interface"
    fi
    mapfile -t AllProfiles < <(list_profiles)
    mapfile -t Profiles < <(grep -Fl "$InterfaceLine" "${AllProfiles[@]}")
84
    if (( ${#Profiles[@]} )); then
85
        do_debug sd_call stop "${Profiles[@]}" 2> >(grep -Fv 'not loaded' >&2)
86
    fi
87
    do_debug sd_call start "$1"
88
89
90
}

unit_enable() {
91
92
93
94
95
96
    local unit=$(systemd-escape --template=netctl@.service "$1") target
    load_profile "$1"

    target="@systemdsystemconfdir@/multi-user.target.wants/$unit"
    if [[ -e $target ]]; then
        report_error "The profile '$1' is already enabled"
97
98
        return 1
    fi
99
100
101
102
103
104
105
106
107
108
    do_readable mkdir -p "$(dirname "$target")"
    ln -vs "@systemdsystemunitdir@/netctl@.service" "$target"

    target="@systemdsystemconfdir@/$unit.d/profile.conf"
    do_readable mkdir -p "$(dirname "$target")"
    do_readable touch "$target"
    echo "[Unit]" > "$target"
    if [[ $Description ]]; then
        echo "Description=$Description" >> "$target"
    fi
109
    declare -p BindsToInterfaces &> /dev/null || BindsToInterfaces=$Interface
Jouke Witteveen's avatar
Jouke Witteveen committed
110
    if (( ${#BindsToInterfaces[@]} )); then
Jouke Witteveen's avatar
Jouke Witteveen committed
111
        : ${InterfaceRoot=sys/subsystem/net/devices/}
112
        printf "BindsTo=$(systemd-escape "$InterfaceRoot")%s.device\n" \
113
               $(systemd-escape "${BindsToInterfaces[@]}") >> "$target"
114
        printf "After=$(systemd-escape "$InterfaceRoot")%s.device\n" \
115
               $(systemd-escape "${BindsToInterfaces[@]}") >> "$target"
116
    fi
Jouke Witteveen's avatar
Jouke Witteveen committed
117
    if (( ${#After[@]} )); then
118
        printf 'After=netctl@%s.service\n' \
119
               $(systemd-escape "${After[@]}") >> "$target"
120
    fi
121
    report_notice "generated '$target'"
122
}
Jim Pryor's avatar
Jim Pryor committed
123

124
unit_disable() {
125
126
127
    local unit=$(systemd-escape --template=netctl@.service "$1")
    rm -vfd "@systemdsystemconfdir@"{/multi-user.target.wants,}"/$unit" \
            "@systemdsystemconfdir@/$unit.d"{/profile.conf,}
128
129
}

130
131
132
133
134
unit_reenable() {
    unit_disable "$1"
    unit_enable "$1"
}

135
136
137
138
139
140
141
142
143
144
wait_online() {
    local profile="$1"
    if sd_call "is-active --quiet" "$profile"; then
        timeout_wait "${TIMEOUT_ONLINE:-120}" \
                     '[[ $(sd_status_text "$profile") == "online" ]]'
    else
        return 1
    fi
}

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

case $# in
  1)
    case $1 in
      --version)
        report_notice "netctl version $NETCTL_VERSION";;
      --help)
        usage;;
      list)
        list;;
      store|restore)
        ensure_root "$(basename "$0")"
        "$1";;
      stop-all)
        stop_all;;
      *)
        exit_error "$(usage)";;
    esac;;
  2)
    case $1 in
165
      start|stop|restart|is-active|status|is-enabled)
166
        sd_call "$1" "$2";;
167
168
      switch-to)
        ensure_root "$(basename "$0")"
169
        verify_profile "$2"
170
        switch_to "$2";;
171
      enable|disable|reenable)
172
        ensure_root "$(basename "$0")"
173
174
175
        if [[ $1 != "disable" ]]; then
            verify_profile "$2"
        fi
176
        "unit_$1" "$2"
177
        if systemd-notify --booted; then
178
179
            systemctl daemon-reload
        fi;;
180
181
      edit)
        exec ${EDITOR:-nano} "$PROFILE_DIR/$2";;
182
183
      verify)
        verify_profile "$2";;
184
185
      wait-online)
        wait_online "$2";;
186
187
188
189
190
      *)
        exit_error "$(usage)";;
    esac;;
  *)
    exit_error "$(usage)";;
James Rayner's avatar
James Rayner committed
191
esac
192

Jim Pryor's avatar
Jim Pryor committed
193
194

# vim: ft=sh ts=4 et sw=4: