FS.pm 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # $OpenBSD: FS.pm,v 1.5 2015/04/29 08:18:42 espie Exp $
  2. # Copyright (c) 2008 Marc Espie <espie@openbsd.org>
  3. #
  4. # Permission to use, copy, modify, and distribute this software for any
  5. # purpose with or without fee is hereby granted, provided that the above
  6. # copyright notice and this permission notice appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. use strict;
  16. use warnings;
  17. package OpenBSD::FS::File;
  18. sub new
  19. {
  20. my ($class, $filename, $type, $owner, $group) = @_;
  21. bless {path =>$filename, type => $type, owner => $owner,
  22. group => $group}, $class
  23. }
  24. sub type
  25. {
  26. shift->{type};
  27. }
  28. sub path
  29. {
  30. shift->{path};
  31. }
  32. sub owner
  33. {
  34. shift->{owner};
  35. }
  36. sub group
  37. {
  38. shift->{group};
  39. }
  40. package OpenBSD::FS;
  41. my $destdir;
  42. use OpenBSD::Mtree;
  43. use File::Find;
  44. use File::Spec;
  45. use File::Basename;
  46. use OpenBSD::IdCache;
  47. use Config;
  48. # existing files are classified according to the following routine
  49. sub get_type
  50. {
  51. my $filename = shift;
  52. if (-d $filename && !-l $filename) {
  53. return "directory";
  54. } elsif (is_subinfo($filename)) {
  55. return "subinfo";
  56. } elsif (is_info($filename)) {
  57. return "info";
  58. } elsif (is_dir($filename)) {
  59. return "dir";
  60. } elsif (is_manpage($filename)) {
  61. return "manpage";
  62. } elsif (is_library($filename)) {
  63. return "library";
  64. } elsif (is_plugin($filename)) {
  65. return "plugin";
  66. } elsif (is_binary($filename)) {
  67. return "binary";
  68. } else {
  69. return "file";
  70. }
  71. }
  72. # symlinks are usually given in a DESTDIR setting, any operation
  73. # beyond filename checking gets through resolve_link
  74. sub resolve_link
  75. {
  76. my $filename = shift;
  77. my $level = shift || 0;
  78. if (-l $filename) {
  79. my $l = readlink($filename);
  80. if ($level++ > 14) {
  81. print STDERR "Symlink too deep: $filename\n";
  82. return $filename;
  83. }
  84. if ($l =~ m|^/|) {
  85. return $destdir.resolve_link($l, $level);
  86. } else {
  87. return resolve_link(File::Spec->catfile(dirname($filename),$l), $level);
  88. }
  89. } else {
  90. return $filename;
  91. }
  92. }
  93. sub is_shared_object
  94. {
  95. my $filename = shift;
  96. $filename = resolve_link($filename);
  97. my $check=`/usr/bin/objdump -h \Q$filename\E 2>/dev/null`;
  98. chomp $check;
  99. if ($check =~m/ .note.openbsd.ident / && $check !~m/ .interp /) {
  100. return 1;
  101. } else {
  102. return 0;
  103. }
  104. }
  105. sub is_library
  106. {
  107. my $filename = shift;
  108. return 0 unless $filename =~ m/\/lib[^\/]*\.so\.\d+\.\d+$/;
  109. return is_shared_object($filename);
  110. }
  111. sub is_binary
  112. {
  113. my $filename = shift;
  114. return 0 if -l $filename or ! -x $filename;
  115. my $check=`/usr/bin/objdump -h \Q$filename\E 2>/dev/null`;
  116. chomp $check;
  117. if ($check =~m/ .note.openbsd.ident /) {
  118. return 1;
  119. } else {
  120. return 0;
  121. }
  122. }
  123. sub is_plugin
  124. {
  125. my $filename = shift;
  126. return 0 unless $filename =~ m/\.so$/;
  127. return is_shared_object($filename);
  128. }
  129. sub is_info
  130. {
  131. my $filename = shift;
  132. return 0 unless $filename =~ m/\.info$/ or $filename =~ m/info\/[^\/]+$/;
  133. $filename = resolve_link($filename);
  134. open my $fh, '<', $filename or return 0;
  135. my $tag = <$fh>;
  136. return 0 unless defined $tag;
  137. my $tag2 = <$fh>;
  138. $tag .= $tag2 if defined $tag2;
  139. close $fh;
  140. if ($tag =~ /^This\sis\s.*,\sproduced\sby\s[Mm]akeinfo(?:\sversion\s|\-)?.*[\d\s]from/s ||
  141. $tag =~ /^Dies\sist\s.*,\shergestellt\svon\s[Mm]akeinfo(?:\sVersion\s|\-)?.*[\d\s]aus/s) {
  142. return 1;
  143. } else {
  144. return 0;
  145. }
  146. }
  147. sub is_manpage
  148. {
  149. local $_ = shift;
  150. if (m,/man/(?:[^/]*?/)?man(.*?)/[^/]+\.\1[[:alpha:]]?(?:\.gz|\.Z)?$,) {
  151. return 1;
  152. }
  153. if (m,/man/(?:[^/]*?/)?man3p/[^/]+\.3(?:\.gz|\.Z)?$,) {
  154. return 1;
  155. }
  156. if (m,/man/(?:[^/]*/)?cat.*?/[^/]+\.0(?:\.gz|\.Z)?$,) {
  157. return 1;
  158. }
  159. if (m,/man/(?:[^/]*/)?(?:man|cat).*?/[^/]+\.tbl(?:\.gz|\.Z)?$,) {
  160. return 1;
  161. }
  162. return 0;
  163. }
  164. sub is_dir
  165. {
  166. my $filename = shift;
  167. return 0 unless $filename =~ m/\/dir$/;
  168. $filename = resolve_link($filename);
  169. open my $fh, '<', $filename or return 0;
  170. my $tag = <$fh>;
  171. chomp $tag;
  172. $tag.=" ".<$fh>;
  173. chomp $tag;
  174. $tag.=" ".<$fh>;
  175. close $fh;
  176. if ($tag =~ /^(?:\-\*\- Text \-\*\-\s+)?This is the file .*, which contains the topmost node of the Info hierarchy/) {
  177. return 1;
  178. } else {
  179. return 0;
  180. }
  181. }
  182. sub is_subinfo
  183. {
  184. my $filename = shift;
  185. if ($filename =~ m/^(.*\.info)\-\d+$/ or
  186. $filename =~ m/^(.*info\/[^\/]+)\-\d+$/) {
  187. return is_info($1);
  188. }
  189. if ($filename =~ m/^(.*)\.\d+in$/) {
  190. return is_info("$1.info");
  191. }
  192. return 0;
  193. }
  194. sub undest
  195. {
  196. my $filename = shift;
  197. if ($filename =~ m/^\Q$destdir\E/) {
  198. $filename = $';
  199. }
  200. $filename='/' if $filename eq '';
  201. return $filename;
  202. }
  203. # check that $fullname is not the only entry in its directory
  204. sub has_other_entry
  205. {
  206. my $fullname = shift;
  207. use Symbol;
  208. my $dir = gensym;
  209. opendir($dir, dirname($fullname)) or return 0;
  210. while (my $e = readdir($dir)) {
  211. next if $e eq '.' or $e eq '..';
  212. next if $e eq basename($fullname);
  213. return 1;
  214. }
  215. return 0;
  216. }
  217. # zap directories going up if there is nothing but that filename.
  218. # used to zap .perllocal, dir, and other stuff.
  219. sub zap_dirs
  220. {
  221. my ($dirs, $fullname) = @_;
  222. return if has_other_entry($fullname);
  223. my $d = dirname($fullname);
  224. return if $d eq $destdir;
  225. delete $dirs->{undest($d)};
  226. zap_dirs($dirs, $d);
  227. }
  228. # find all objects that need registration, mark them according to type.
  229. sub scan_destdir
  230. {
  231. my %files;
  232. my %okay_files=map { $_=>1 } split(/\s+/, $ENV{'OKAY_FILES'});
  233. my $installsitearch = $Config{'installsitearch'};
  234. my $archname = $Config{'archname'};
  235. my $installprivlib = $Config{'installprivlib'};
  236. my $installarchlib = $Config{'installarchlib'};
  237. my $uid_lookup = OpenBSD::UnameCache->new;
  238. my $gid_lookup = OpenBSD::GnameCache->new;
  239. find(
  240. sub {
  241. return if defined $okay_files{$File::Find::name};
  242. my $type = get_type($File::Find::name);
  243. if ($type eq "dir" or
  244. $type eq 'subinfo' or
  245. $File::Find::name =~ m,\Q$installsitearch\E/auto/.*/\.packlist$, or
  246. $File::Find::name =~ m,\Q$installarchlib/perllocal.pod\E$, or
  247. $File::Find::name =~ m,\Q$installsitearch/perllocal.pod\E$, or
  248. $File::Find::name =~ m,\Q$installprivlib/$archname/perllocal.pod\E$,) {
  249. zap_dirs(\%files, $File::Find::name);
  250. return;
  251. }
  252. return if $File::Find::name =~ m/pear\/lib\/\.(?:filemap|lock)$/;
  253. my $path = undest($File::Find::name);
  254. my ($uid, $gid) = (lstat $_)[4,5];
  255. $path =~ s,^/etc/X11/app-defaults\b,/usr/local/lib/X11/app-defaults,;
  256. $files{$path} = OpenBSD::FS::File->new($path, $type,
  257. $uid_lookup->lookup($uid),
  258. $gid_lookup->lookup($gid));
  259. }, $destdir);
  260. zap_dirs(\%files, $destdir.'/etc/X11/app-defaults');
  261. return \%files;
  262. }
  263. # build a hash of files needing registration
  264. sub get_files
  265. {
  266. $destdir = shift;
  267. my $files = scan_destdir();
  268. my $mtree = {};
  269. OpenBSD::Mtree::parse($mtree, '/', '/etc/mtree/4.4BSD.dist');
  270. OpenBSD::Mtree::parse($mtree, '/', '/etc/mtree/BSD.x11.dist');
  271. $mtree->{'/usr/local/lib/X11'} = 1;
  272. $mtree->{'/usr/local/include/X11'} = 1;
  273. $mtree->{'/usr/local/lib/X11/app-defaults'} = 1;
  274. # zap /usr/libdata/xxx from perl install
  275. $mtree->{$Config{'installarchlib'}} = 1;
  276. $mtree->{dirname($Config{'installarchlib'})} = 1;
  277. # make sure main mtree is removed
  278. for my $d (keys %$mtree) {
  279. delete $files->{$d}
  280. }
  281. return $files;
  282. }
  283. 1;