Line 0
Link Here
|
0 |
- |
1 |
# -*-eselect-*- vim: ft=eselect |
|
|
2 |
# Copyright (c) 2005-2013 Gentoo Foundation |
3 |
# |
4 |
# This file is part of the 'eselect' tools framework. |
5 |
# |
6 |
# eselect is free software: you can redistribute it and/or modify it under the |
7 |
# terms of the GNU General Public License as published by the Free Software |
8 |
# Foundation, either version 2 of the License, or (at your option) any later |
9 |
# version. |
10 |
# |
11 |
# eselect is distributed in the hope that it will be useful, but WITHOUT ANY |
12 |
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
13 |
# A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
14 |
# |
15 |
# You should have received a copy of the GNU General Public License along with |
16 |
# eselect. If not, see <http://www.gnu.org/licenses/>. |
17 |
|
18 |
# This library is for managing a common binary symlink like /bin/sh |
19 |
# or /usr/bin/pinentry. To use it, you need to set the following |
20 |
# variables: |
21 |
# |
22 |
# SYMLINK_PATH is the name of symlink being created, e.g. "/bin/sh". |
23 |
# The path should be absolute, without EPREFIX (it will be added). |
24 |
# |
25 |
# SYMLINK_TARGETS is the list (bash array) of targets being available. |
26 |
# The paths should be relative to ${SYMLINK_PATH}. Only basenames |
27 |
# of the targets will be displayed to user. Best (preferred) targets |
28 |
# should go earlier on the list. |
29 |
# |
30 |
# SYMLINK_DESCRIPTION is the human-friendly name of the symlink, e.g. |
31 |
# "POSIX shell". It will be used in the context of "implementation" |
32 |
# or "symlink". Defaults to basename of ${SYMLINK_PATH}. |
33 |
# |
34 |
# SYMLINK_CRUCIAL should be set to a non-null value if existence of no |
35 |
# targets should trigger a fatal error rather than silent symlink |
36 |
# removal. |
37 |
|
38 |
# Maintainer: mgorny@gentoo.org |
39 |
# Based on the work of: |
40 |
# - Erik Hahn; bug #214817 |
41 |
# - Samuli Suominen <ssuominen@gentoo.org>; eselect-pinentry |
42 |
|
43 |
## Global variables ## |
44 |
|
45 |
if [[ ! ${SYMLINK_PATH} ]]; then |
46 |
die "SYMLINK_PATH needs to be set by eselect module." |
47 |
fi |
48 |
|
49 |
if [[ ! ${SYMLINK_TARGETS[@]} ]]; then |
50 |
die "SYMLINK_TARGETS need to be set by eselect module." |
51 |
fi |
52 |
|
53 |
: ${SYMLINK_DESCRIPTION:-${SYMLINK_PATH##*/}} |
54 |
|
55 |
## Functions ## |
56 |
|
57 |
# find a list of symlink targets, best first |
58 |
find_targets() { |
59 |
local basedir=${SYMLINK_PATH%/*} |
60 |
TARGETS=() |
61 |
|
62 |
local t |
63 |
for t in "${SYMLINK_TARGETS[@]}"; do |
64 |
if [[ -x ${EROOT}${basedir}/${t} ]]; then |
65 |
TARGETS+=( ${t} ) |
66 |
fi |
67 |
done |
68 |
} |
69 |
|
70 |
# set the pinentry symlink |
71 |
set_symlinks() { |
72 |
local target="${1}" targets |
73 |
local basedir=${SYMLINK_PATH%/*} |
74 |
|
75 |
[[ ! -L ${EROOT}${SYMLINK_PATH} && -e ${EROOT}${SYMLINK_PATH} ]] && \ |
76 |
die -q "${EROOT}${SYMLINK_PATH} is not a symlink!" |
77 |
|
78 |
if is_number "${target}" && [[ ${target} -ge 1 ]]; then |
79 |
local TARGETS |
80 |
|
81 |
find_targets |
82 |
target=${TARGETS[target-1]} |
83 |
elif [[ ! -x ${EROOT}${basedir}/${target} ]]; then |
84 |
# try basename matching |
85 |
local TARGETS t |
86 |
find_targets |
87 |
|
88 |
for t in "${TARGETS[@]}"; do |
89 |
if [[ ${t##*/} == ${target} ]]; then |
90 |
target=${t} |
91 |
break |
92 |
fi |
93 |
done |
94 |
fi |
95 |
|
96 |
if [[ -x ${EROOT}${basedir}/${target} ]]; then |
97 |
local tmpf=${EROOT}${SYMLINK_PATH}.new |
98 |
# we could use 'ln -f' to directly replace the symlink |
99 |
# but 'mv' is an atomic operation so it should be more fault-proof |
100 |
|
101 |
ln -s "${target}" "${tmpf}" || \ |
102 |
die -q "Unable to create temporary symlink" |
103 |
if ! mv "${tmpf}" "${EROOT}${SYMLINK_PATH}"; then |
104 |
rm -f "${tmpf}" # cleanup |
105 |
die -q "Unable to replace ${EROOT}${SYMLINK_PATH} symlink with ${target}" |
106 |
fi |
107 |
else |
108 |
die -q "Target '${target}' doesn't appear to be valid!" |
109 |
fi |
110 |
} |
111 |
|
112 |
### show action ### |
113 |
|
114 |
describe_show() { |
115 |
echo "Show the current ${SYMLINK_DESCRIPTION} implementation" |
116 |
} |
117 |
|
118 |
do_show() { |
119 |
[[ ${@} ]] && die -q "Too many parameters" |
120 |
|
121 |
write_list_start "Current ${SYMLINK_DESCRIPTION} implementation:" |
122 |
if [[ -L ${EROOT}${SYMLINK_PATH} ]]; then |
123 |
local t=$(readlink "${EROOT}${SYMLINK_PATH}") |
124 |
write_kv_list_entry "${t##*/}" "" |
125 |
elif [[ -e ${EROOT}${SYMLINK_PATH} ]]; then |
126 |
write_kv_list_entry "(not a symlink)" "" |
127 |
else |
128 |
write_kv_list_entry "(unset)" "" |
129 |
fi |
130 |
} |
131 |
|
132 |
### list action ### |
133 |
|
134 |
describe_list() { |
135 |
echo "List available ${SYMLINK_DESCRIPTION} implementations" |
136 |
} |
137 |
|
138 |
do_list() { |
139 |
[[ ${@} ]] && die -q "Too many parameters" |
140 |
|
141 |
local i TARGETS |
142 |
find_targets |
143 |
|
144 |
write_list_start "Available ${SYMLINK_DESCRIPTION} implementations:" |
145 |
if [[ ${TARGETS[@]} ]]; then |
146 |
local curr=$(readlink "${EROOT}${SYMLINK_PATH}") |
147 |
|
148 |
for (( i = 0; i < ${#TARGETS[@]}; i++ )) ; do |
149 |
[[ ${TARGETS[${i}]##*/} == ${curr##*/} ]] && \ |
150 |
TARGETS[${i}]+=" $(highlight '*')" |
151 |
done |
152 |
write_numbered_list "${TARGETS[@]##*/}" |
153 |
else |
154 |
write_kv_list_entry "(none found)" "" |
155 |
fi |
156 |
} |
157 |
|
158 |
### set action ### |
159 |
|
160 |
describe_set() { |
161 |
echo "Set a new ${SYMLINK_DESCRIPTION} implementation" |
162 |
} |
163 |
|
164 |
describe_set_options() { |
165 |
echo "target : Target name, number (from 'list' action) or path" |
166 |
} |
167 |
|
168 |
describe_set_parameters() { |
169 |
echo "<target>" |
170 |
} |
171 |
|
172 |
do_set() { |
173 |
if [[ ${#} != 1 ]]; then |
174 |
die -q "set takes exactly one parameter" |
175 |
else |
176 |
set_symlinks "${1}" |
177 |
fi |
178 |
} |
179 |
|
180 |
### update action ### |
181 |
|
182 |
describe_update() { |
183 |
echo "Automatically update the ${SYMLINK_DESCRIPTION} implementation" |
184 |
} |
185 |
|
186 |
describe_update_options() { |
187 |
echo "--if-unset : do not override existing implementation" |
188 |
} |
189 |
|
190 |
do_update() { |
191 |
[[ ${1} == ifunset ]] && set -- --if-unset "${@:2}" |
192 |
|
193 |
if [[ ( ${1} && ${1} != '--if-unset' ) || ${2} ]] |
194 |
then |
195 |
die -q "usage error" |
196 |
fi |
197 |
|
198 |
if [[ ${1} == '--if-unset' && -L ${EROOT}${SYMLINK_PATH} \ |
199 |
&& -x ${EROOT}${SYMLINK_PATH} ]] |
200 |
then |
201 |
return |
202 |
fi |
203 |
|
204 |
local TARGETS |
205 |
find_targets |
206 |
|
207 |
if [[ ! ${TARGETS[@]} ]]; then |
208 |
if [[ ${SYMLINK_CRUCIAL} ]]; then |
209 |
die "No targets for ${EROOT}${SYMLINK_PATH}, system likely broken." |
210 |
else |
211 |
rm -f "${EROOT}${SYMLINK_PATH}" |
212 |
fi |
213 |
fi |
214 |
|
215 |
set_symlinks "${TARGETS[0]}" |
216 |
} |
217 |
|
218 |
# vim:ts=4:sts=4:sw=4 |