ResourceFinder.vala 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using Invercargill;
  2. namespace Usm {
  3. public class ResourceFinder {
  4. public Paths paths { get; set; }
  5. public ResourceFinder(Paths? paths = null) {
  6. this.paths = paths ?? new Paths();
  7. }
  8. public bool has_resource(ResourceRef resource_ref) {
  9. return locate_resource(resource_ref) != null;
  10. }
  11. public string? locate_resource(ResourceRef resource_ref) {
  12. switch (resource_ref.resource_type) {
  13. case ResourceType.ROOT_PATH:
  14. return locate_rootpath(resource_ref);
  15. case ResourceType.PATH:
  16. return locate_path(resource_ref);
  17. case ResourceType.OPTIONAL:
  18. return locate_opt(resource_ref);
  19. case ResourceType.RESOURCE:
  20. return locate_res(resource_ref);
  21. case ResourceType.CONFIGURATION:
  22. return locate_cfg(resource_ref);
  23. case ResourceType.BINARY:
  24. return locate_bin(resource_ref);
  25. case ResourceType.SUPER_BINARY:
  26. return locate_sbin(resource_ref);
  27. case ResourceType.LIBRARY:
  28. return locate_lib(resource_ref);
  29. case ResourceType.LIBRARY_EXECUTABLE:
  30. return locate_libexec(resource_ref);
  31. case ResourceType.LIBRARY_RESOURCE:
  32. return locate_libres(resource_ref);
  33. case ResourceType.CANONICAL_LIBRARY:
  34. return locate_canonlib(resource_ref);
  35. case ResourceType.CANONICAL_LIBRARY_RESOURCE:
  36. return locate_canonlibres(resource_ref);
  37. case ResourceType.GIO_MODULE:
  38. return locate_gio(resource_ref);
  39. case ResourceType.INFO_PAGE:
  40. return locate_info(resource_ref);
  41. case ResourceType.MANUAL_PAGE:
  42. return locate_man(resource_ref);
  43. case ResourceType.LOCALE:
  44. return locate_locale(resource_ref);
  45. case ResourceType.APPLICATION:
  46. return locate_app(resource_ref);
  47. case ResourceType.INCLUDE:
  48. return locate_inc(resource_ref);
  49. case ResourceType.PKG_CONFIG:
  50. return locate_pc(resource_ref);
  51. case ResourceType.VALA_API:
  52. return locate_vapi(resource_ref);
  53. case ResourceType.GOBJECT_IR:
  54. return locate_gir(resource_ref);
  55. case ResourceType.TYPELIB:
  56. return locate_typelib(resource_ref);
  57. case ResourceType.TAG:
  58. return locate_tag(resource_ref);
  59. default:
  60. assert_not_reached();
  61. }
  62. }
  63. private string? locate_tag(ResourceRef resource) {
  64. if(Tag.read(resource.resource) != null) {
  65. return paths.get_tag_file_path(resource.resource);
  66. }
  67. return null;
  68. }
  69. private string? locate_lib(ResourceRef resource) {
  70. var via_ldconfig = locate_lib_ldconfig(resource);
  71. if(via_ldconfig != null) {
  72. return via_ldconfig;
  73. }
  74. // musl systems have no `ldconfig -p` output to consult: fall
  75. // back to the conventional library directories
  76. foreach(var directory in new string[] { "/lib", "/usr/lib", "/lib64", "/usr/lib64" }) {
  77. var file = File.new_build_filename(directory, resource.resource);
  78. if(file.query_exists()) {
  79. return file.get_path();
  80. }
  81. }
  82. return null;
  83. }
  84. private string? locate_lib_ldconfig(ResourceRef resource) {
  85. try {
  86. var proc = new Subprocess.newv(new string[] { "ldconfig", "-p" },
  87. SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_SILENCE);
  88. var pipe = new DataInputStream(proc.get_stdout_pipe());
  89. string line = null;
  90. while((line = pipe.read_line()) != null) {
  91. if(line.has_prefix("\t")) {
  92. var name = line.substring(1).split(" ", 2)[0];
  93. if(resource.resource == name) {
  94. return line.substring(1).split("=>", 2)[1].chomp().chug();
  95. }
  96. }
  97. }
  98. proc.wait_check();
  99. }
  100. catch(Error e) {
  101. // busybox/musl ldconfig doesn't support -p; the fallback in
  102. // locate_lib handles it — suppress the noise
  103. }
  104. return null;
  105. }
  106. private string? locate_canonlib(ResourceRef resource) {
  107. try {
  108. var proc = new Subprocess.newv(new string[] { "ldconfig", "-p" },
  109. SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_SILENCE);
  110. var pipe = new DataInputStream(proc.get_stdout_pipe());
  111. string line = null;
  112. while((line = pipe.read_line()) != null) {
  113. if(line.has_prefix("\t")) {
  114. var name = line.substring(1).split(" ", 2)[0];
  115. // Only return true for libraries found in the canonical lib directory (e.g. not in /lib64)
  116. if(resource.resource == name && (name.has_prefix("/usr/lib") || name.has_prefix("/lib"))) {
  117. return line.substring(1).split("=>", 2)[1].chomp().chug();
  118. }
  119. }
  120. }
  121. proc.wait_check();
  122. }
  123. catch(Error e) {
  124. warning(@"Error checking for resource $resource: $(e.message)");
  125. }
  126. return null;
  127. }
  128. private string? locate_bin(ResourceRef resource) {
  129. var env_paths = Environment.get_variable("PATH").split(":");
  130. foreach (var path in env_paths) {
  131. var file = File.new_build_filename(paths.destination, path, resource.resource);
  132. if(file.query_exists()) {
  133. return file.get_path();
  134. }
  135. }
  136. return null;
  137. }
  138. private string? locate_path(ResourceRef resource) {
  139. var file = File.new_build_filename(paths.destination, paths.prefix, resource.resource);
  140. return file.query_exists() ? file.get_path() : null;
  141. }
  142. private string? locate_rootpath(ResourceRef resource) {
  143. var file = File.new_build_filename(paths.destination, resource.resource);
  144. return file.query_exists() ? file.get_path() : null;
  145. }
  146. private string? locate_res(ResourceRef resource) {
  147. var file = File.new_build_filename(paths.destination, paths.prefix, paths.data, resource.resource);
  148. return file.query_exists() ? file.get_path() : null;
  149. }
  150. private string? locate_opt(ResourceRef resource) {
  151. var file = File.new_build_filename(paths.destination, "opt", resource.resource);
  152. return file.query_exists() ? file.get_path() : null;
  153. }
  154. private string? locate_cfg(ResourceRef resource) {
  155. var file = File.new_build_filename(paths.destination, paths.sys_config, resource.resource);
  156. return file.query_exists() ? file.get_path() : null;
  157. }
  158. private string? locate_libres(ResourceRef resource) {
  159. var search = new string[] { "/usr/lib", "/usr/lib64", "/lib", "/lib64" };
  160. foreach (var path in search) {
  161. var file = File.new_build_filename(paths.destination, path, resource.resource);
  162. if(file.query_exists()) {
  163. return file.get_path();
  164. }
  165. }
  166. return null;
  167. }
  168. private string? locate_canonlibres(ResourceRef resource) {
  169. var search = new string[] { "/usr/lib", "/lib" };
  170. foreach (var path in search) {
  171. var file = File.new_build_filename(paths.destination, path, resource.resource);
  172. if(file.query_exists()) {
  173. return file.get_path();
  174. }
  175. }
  176. return null;
  177. }
  178. private string? locate_gio(ResourceRef resource) {
  179. var search = Iterate.these("/usr/lib64/gio/modules", "/usr/lib/gio/modules");
  180. // Debian-style multiarch keeps GIO modules in
  181. // /usr/lib/<triple>/gio/modules, which no fixed path covers:
  182. // enumerate whatever multiarch directories exist
  183. try {
  184. foreach(var entry in Iterate.directory("/usr/lib")) {
  185. if(entry.contains("-linux-")) {
  186. search = search.concat(Wrap.array(new string[] { @"/usr/lib/$entry/gio/modules" }));
  187. }
  188. }
  189. }
  190. catch(FileError e) {
  191. }
  192. foreach (var path in search) {
  193. var file = File.new_build_filename(paths.destination, path, resource.resource);
  194. if(file.query_exists()) {
  195. return file.get_path();
  196. }
  197. }
  198. return null;
  199. }
  200. private string? locate_app(ResourceRef resource) {
  201. var file = File.new_build_filename("/usr/share/applications", resource.resource);
  202. return file.query_exists() ? file.get_path() : null;
  203. }
  204. private string? locate_inc(ResourceRef resource) {
  205. var file = File.new_build_filename("/usr/include", resource.resource);
  206. return file.query_exists() ? file.get_path() : null;
  207. }
  208. private string? locate_sbin(ResourceRef resource) {
  209. var search = new string[] { "/usr/sbin", "/sbin" };
  210. foreach (var path in search) {
  211. var file = File.new_build_filename(paths.destination, path, resource.resource);
  212. if(file.query_exists()) {
  213. return file.get_path();
  214. }
  215. }
  216. return null;
  217. }
  218. private string? locate_libexec(ResourceRef resource) {
  219. var file = File.new_build_filename("/usr/libexec", resource.resource);
  220. return file.query_exists() ? file.get_path() : null;
  221. }
  222. private string? locate_info(ResourceRef resource) {
  223. var file = File.new_build_filename("/usr/share/info", resource.resource);
  224. return file.query_exists() ? file.get_path() : null;
  225. }
  226. private string? locate_man(ResourceRef resource) {
  227. var file = File.new_build_filename("/usr/share/man", resource.resource);
  228. return file.query_exists() ? file.get_path() : null;
  229. }
  230. private string? locate_locale(ResourceRef resource) {
  231. var file = File.new_build_filename("/usr/share/locale", resource.resource);
  232. return file.query_exists() ? file.get_path() : null;
  233. }
  234. private string? locate_vapi(ResourceRef resource) {
  235. var search = new string[] { "/usr/share/vala/vapi", "/usr/share/vala-0.56/vapi" };
  236. foreach (var path in search) {
  237. var file = File.new_build_filename(paths.destination, path, resource.resource);
  238. if(file.query_exists()) {
  239. return file.get_path();
  240. }
  241. }
  242. return null;
  243. }
  244. private string? locate_pc(ResourceRef resource) {
  245. var search = Iterate.these("/usr/lib/pkgconfig", "/usr/lib64/pkgconfig", "/usr/share/pkgconfig");
  246. // Debian-style multiarch keeps pkg-config files in
  247. // /usr/lib/<triple>/pkgconfig, which no fixed path covers:
  248. // enumerate whatever multiarch directories exist
  249. try {
  250. foreach(var entry in Iterate.directory("/usr/lib")) {
  251. if(entry.contains("-linux-")) {
  252. search = search.concat(Wrap.array(new string[] { @"/usr/lib/$entry/pkgconfig" }));
  253. }
  254. }
  255. }
  256. catch(FileError e) {
  257. }
  258. var env = Environment.get_variable("PKG_CONFIG_PATH");
  259. if(env != null) {
  260. search = search.concat(Wrap.array(env.split(":")));
  261. }
  262. foreach (var path in search) {
  263. var file = File.new_build_filename(paths.destination, path, resource.resource);
  264. if(file.query_exists()) {
  265. return file.get_path();
  266. }
  267. }
  268. return null;
  269. }
  270. private string? locate_gir(ResourceRef resource) {
  271. var file = File.new_build_filename("/usr/share/gir", resource.resource);
  272. return file.query_exists() ? file.get_path() : null;
  273. }
  274. private string? locate_typelib(ResourceRef resource) {
  275. var search = new string[] { "/usr/lib64/girepository-1.0", "/usr/lib/girepository-1.0", "/lib64/girepository-1.0", "/lib/girepository-1.0" };
  276. foreach (var path in search) {
  277. var file = File.new_build_filename(paths.destination, path, resource.resource);
  278. if(file.query_exists()) {
  279. return file.get_path();
  280. }
  281. }
  282. return null;
  283. }
  284. }
  285. }