summaryrefslogtreecommitdiffstats
path: root/find_depends.function
blob: 6e7badea8e8e18e239e563ce70c0dc2c85731893 (plain) (blame)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#---------------------------------------------------------------------
## @Synopsis Set of functions for dependency discovery
##
## @Copyright Source Mage Team
#---------------------------------------------------------------------

#---------------------------------------------------------------------
## Find all spells that depend on at least one of a given list of
## libtool archives and a given list of shared objects.
##
## @param dependencies_var: output variable name
## @param libtool_names: a list of libtool archive names
## @param so_names: a list of shared object names
## @param excluded_spells: a list of spells to be excluded
## @stdout progress messages
#---------------------------------------------------------------------
function find_libtool_so_dependencies() {
  local dependencies_var="$1" &&
  local libtool_names="$2" &&
  local so_names="$3" &&
  local excluded_spells="$4" &&

  LANG= &&
  local spells=$(gaze installed | cut -d: -f1) &&
  local spell_count=$(wc -l <<< "$spells") &&
  local spell_index=0 &&
  for spell in $spells; do
    ((spell_index++)) &&
    message -n "${DEFAULT_COLOR}[${spell_index}/${spell_count} ${spell}]\e[K\r" &&
    if list_find "$excluded_spells" "$spell"; then
      continue
    fi &&
    if spell_has_libtool_dependency $spell "$libtool_names"; then
      list_add "$dependencies_var" $spell &&
      continue
    fi &&
    if spell_has_shared_object_dependency $spell "$so_names"; then
      list_add "$dependencies_var" "$spell"
    fi
  done &&
  message
}

#---------------------------------------------------------------------
## Find all spells that depend on at least one of a given list of
## libtool archives
##
## @param dependencies_var: output variable name
## @param libtool_names: a list of libtool archive names
## @param excluded_spells: a list of spells to be excluded
## @stdout progress messages
#---------------------------------------------------------------------
function find_libtool_dependencies() {
  local dependencies_var="$1" &&
  local libtool_names="$2" &&
  local excluded_spells="$3" &&

  LANG= &&
  local spells=$(gaze installed | cut -d: -f1) &&
  local spell_count=$(wc -l <<< "$spells") &&
  local spell_index=0 &&
  for spell in $spells; do
    ((spell_index++)) &&
    message -n "${DEFAULT_COLOR}[${spell_index}/${spell_count} ${spell}]\e[K\r" &&
    if list_find "$excluded_spells" "$spell"; then
      continue
    fi &&
    if spell_has_libtool_dependency $spell "$libtool_names"; then
      list_add "$dependencies_var" $spell
    fi
  done &&
  message
}

#---------------------------------------------------------------------
## Find all spells that depend on at least one of a given list of
## shared objects.
##
## @param dependencies_var: output variable name
## @param so_names: a list of shared object names
## @param excluded_spells: a list of spells to be excluded
## @stdout progress messages
#---------------------------------------------------------------------
function find_shared_object_dependencies() {
  local dependencies_var="$1" &&
  local so_names="$2" &&
  local excluded_spells="$3" &&

  LANG= &&
  local spells=$(gaze installed | cut -d: -f1) &&
  local spell_count=$(wc -l <<< "$spells") &&
  local spell_index=0 &&
  for spell in $spells; do
    ((spell_index++)) &&
    message -n "${DEFAULT_COLOR}[${spell_index}/${spell_count} ${spell}]\e[K\r" &&
    if list_find "$excluded_spells" "$spell"; then
      continue
    fi &&
    if spell_has_shared_object_dependency $spell "$so_names"; then
      list_add "$dependencies_var" "$spell"
    fi
  done &&
  message
}

#---------------------------------------------------------------------
## Determine whether the given spell depends on at least one of a
## given list of libtool archives
##
## @param spell: spell to check for dependency
## @param libtool_names: a list of libtool archive names
## 
## @return 0 if the given spell depends on any of the given libtool archives
## @return 1 if the given spell does not depend on any of the given libtool archives
## @return 2 if any error occurs
#---------------------------------------------------------------------
function spell_has_libtool_dependency() {
  local spell="$1"
  local libtool_names="$2"

  find_spell_libtool_archives "$spell" \
  | xargs grep --quiet --basic-regexp --file=<(sed -e 's/[.[^$\*]/\\&/g' -e 's/.*/^dependency_libs.*&/' <<< "$libtool_names")

  return $(( ${PIPESTATUS[0]} > 0 ? 2 : ${PIPESTATUS[-1]} ))
}

#---------------------------------------------------------------------
## Determine whether the given spell depends on at least one of a
## given list of shared objects
##
## @param spell: spell to check for dependency
## @param so_names: a list of shared object names
## 
## @return 0 if the given spell depends on any of the given shared objects
## @return 1 if the given spell does not depend on any of the given shared objects
## @return 2 if any error occurs
#---------------------------------------------------------------------
function spell_has_shared_object_dependency() {
  local spell="$1"
  local so_names="$2"

  find_spell_dynamically_linked_ELF_objects "$spell" \
  | xargs readelf -d 2> /dev/null \
  | grep --quiet --basic-regexp --file=<(sed -e 's/[.[^$\*]/\\&/g' -e 's/.*/NEEDED)[[:space:]]*Shared library: \\[&/' <<< "$so_names")

  return $(( (${PIPESTATUS[0]} > 0 || ${PIPESTATUS[1]} > 0) ? 2 : ${PIPESTATUS[-1]} ))
}

#---------------------------------------------------------------------
## List all libtool archives installed by a spell
##
## @param spell: spell to list libtool archives for
## @stdout a list of all libtool archives installed by the spell
#---------------------------------------------------------------------
function find_spell_libtool_archives() {
  local -a file_opts
  OPTIND=1
  while getopts ':L' opt; do
    case "$opt" in
      L)
        file_opts+=("--dereference")
        ;;
      \?)
        return 1
        ;;
    esac
  done
  shift $((OPTIND - 1))
  local spell="$1"

  local magic="\
0       search/80       .la\ -\ a\ libtool\ library\ file       libtool library file"

  LANG=
  gaze install "$spell" \
  | file --magic-file <(echo "$magic") "${file_opts[@]}" --files-from - \
  | sed -n -e '/\<libtool library file\>/s/:.*//p'
}

#---------------------------------------------------------------------
## List all shared objects installed by a spell
##
## @param spell: spell to list shared objects for
## @stdout a list of all shared objects installed by the spell
#---------------------------------------------------------------------
function find_spell_shared_objects() {
  local -a file_opts
  OPTIND=1
  while getopts ':L' opt; do
    case $opt in
      L)
        file_opts+=("--dereference")
        ;;
      \?)
        return 1
        ;;
    esac
  done
  shift $((OPTIND - 1))
  local spell="$1"

  local magic="\
0       string          \177ELF         ELF
>5      byte            1               LSB
>>16    leshort         3               shared object,
>5      byte            2               MSB
>>16    beshort         3               shared object,"

  LANG=
  gaze install "$spell" \
  | file --magic-file <(echo "$magic") "${file_opts[@]}" --files-from - \
  | sed -n -e '/\<ELF\>.*\<shared object\>/s/:.*//p'
}

#---------------------------------------------------------------------
## List all dynamically linked ELF objects installed by a spell
##
## @param spell: spell to list dynamically linked ELF objects for
## @stdout a list of all dynamically linked ELF objects installed by the spell
#---------------------------------------------------------------------
function find_spell_dynamically_linked_ELF_objects() {
  local -a file_opts
  OPTIND=1
  while getopts ':L' opt; do
    case "$opt" in
      L)
        file_opts+=("--dereference")
        ;;
      \?)
        return 1
        ;;
    esac
  done
  shift $((OPTIND - 1))
  local spell="$1"

  local magic="\
0       string          \177ELF         ELF"

  LANG=
  gaze install "$spell" \
  | file --magic-file <(echo "$magic") "${file_opts[@]}" --files-from - \
  | sed -n -e '/\<ELF\>.*\<dynamically linked\>/s/:.*//p'
}