dpkg-name.pl 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #!/usr/bin/perl
  2. #
  3. # dpkg-name
  4. #
  5. # Copyright © 1995,1996 Erick Branderhorst <branderh@debian.org>.
  6. # Copyright © 2006-2010, 2012-2015 Guillem Jover <guillem@debian.org>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. use warnings;
  21. use strict;
  22. use File::Basename;
  23. use File::Path qw(make_path);
  24. use Dpkg ();
  25. use Dpkg::Gettext;
  26. use Dpkg::ErrorHandling;
  27. use Dpkg::Version;
  28. use Dpkg::Control;
  29. use Dpkg::Arch qw(get_host_arch);
  30. textdomain('dpkg-dev');
  31. my %options = (
  32. subdir => 0,
  33. destdir => '',
  34. createdir => 0,
  35. overwrite => 0,
  36. symlink => 0,
  37. architecture => 1,
  38. );
  39. sub version()
  40. {
  41. printf(g_("Debian %s version %s.\n"), $Dpkg::PROGNAME, $Dpkg::PROGVERSION);
  42. }
  43. sub usage()
  44. {
  45. printf(g_("Usage: %s [<option>...] <file>...\n"), $Dpkg::PROGNAME);
  46. print(g_("
  47. Options:
  48. -a, --no-architecture no architecture part in filename.
  49. -o, --overwrite overwrite if file exists.
  50. -k, --symlink don't create a new file, but a symlink.
  51. -s, --subdir [dir] move file into subdirectory (use with care).
  52. -c, --create-dir create target directory if not there (use with care).
  53. -?, --help show this help message.
  54. -v, --version show the version.
  55. file.deb changes to <package>_<version>_<architecture>.<package_type>
  56. according to the 'underscores convention'.
  57. "));
  58. }
  59. sub fileexists($)
  60. {
  61. my $filename = shift;
  62. if (-f $filename) {
  63. return 1;
  64. } else {
  65. warning(g_("cannot find '%s'"), $filename);
  66. return 0;
  67. }
  68. }
  69. sub filesame($$)
  70. {
  71. my ($a, $b) = @_;
  72. my @sta = stat($a);
  73. my @stb = stat($b);
  74. # Same device and inode numbers.
  75. return (@sta and @stb and $sta[0] == $stb[0] and $sta[1] == $stb[1]);
  76. }
  77. sub getfields($)
  78. {
  79. my $filename = shift;
  80. # Read the fields
  81. open(my $cdata_fh, '-|', 'dpkg-deb', '-f', '--', $filename)
  82. or syserr(g_('cannot open %s'), $filename);
  83. my $fields = Dpkg::Control->new(type => CTRL_PKG_DEB);
  84. $fields->parse($cdata_fh, sprintf(g_('binary control file %s'), $filename));
  85. close($cdata_fh);
  86. return $fields;
  87. }
  88. sub getarch($$)
  89. {
  90. my ($filename, $fields) = @_;
  91. my $arch = $fields->{Architecture};
  92. if (not $fields->{Architecture} and $options{architecture}) {
  93. $arch = get_host_arch();
  94. warning(g_("assuming architecture '%s' for '%s'"), $arch, $filename);
  95. }
  96. return $arch;
  97. }
  98. sub getname($$$)
  99. {
  100. my ($filename, $fields, $arch) = @_;
  101. my $pkg = $fields->{Package};
  102. my $v = Dpkg::Version->new($fields->{Version});
  103. my $version = $v->as_string(omit_epoch => 1);
  104. my $type = $fields->{'Package-Type'} || 'deb';
  105. my $tname;
  106. if ($options{architecture}) {
  107. $tname = "$pkg\_$version\_$arch.$type";
  108. } else {
  109. $tname = "$pkg\_$version.$type";
  110. }
  111. (my $name = $tname) =~ s/ //g;
  112. if ($tname ne $name) { # control fields have spaces
  113. warning(g_("bad package control information for '%s'"), $filename);
  114. }
  115. return $name;
  116. }
  117. sub getdir($$$)
  118. {
  119. my ($filename, $fields, $arch) = @_;
  120. my $dir;
  121. if (!$options{destdir}) {
  122. $dir = dirname($filename);
  123. if ($options{subdir}) {
  124. my $section = $fields->{Section};
  125. if (!$section) {
  126. $section = 'no-section';
  127. warning(g_("assuming section '%s' for '%s'"), $section,
  128. $filename);
  129. }
  130. if ($section ne 'non-free' and $section ne 'contrib' and
  131. $section ne 'no-section') {
  132. $dir = "unstable/binary-$arch/$section";
  133. } else {
  134. $dir = "$section/binary-$arch";
  135. }
  136. }
  137. } else {
  138. $dir = $options{destdir};
  139. }
  140. return $dir;
  141. }
  142. sub move($)
  143. {
  144. my $filename = shift;
  145. if (fileexists($filename)) {
  146. my $fields = getfields($filename);
  147. unless (exists $fields->{Package}) {
  148. warning(g_("no Package field found in '%s', skipping package"),
  149. $filename);
  150. return;
  151. }
  152. my $arch = getarch($filename, $fields);
  153. my $name = getname($filename, $fields, $arch);
  154. my $dir = getdir($filename, $fields, $arch);
  155. if (! -d $dir) {
  156. if ($options{createdir}) {
  157. if (make_path($dir)) {
  158. info(g_("created directory '%s'"), $dir);
  159. } else {
  160. error(g_("cannot create directory '%s'"), $dir);
  161. }
  162. } else {
  163. error(g_("no such directory '%s', try --create-dir (-c) option"),
  164. $dir);
  165. }
  166. }
  167. my $newname = "$dir/$name";
  168. my @command;
  169. if ($options{symlink}) {
  170. @command = qw(ln -s --);
  171. } else {
  172. @command = qw(mv --);
  173. }
  174. if (filesame($newname, $filename)) {
  175. warning(g_("skipping '%s'"), $filename);
  176. } elsif (-f $newname and not $options{overwrite}) {
  177. warning(g_("cannot move '%s' to existing file"), $filename);
  178. } elsif (system(@command, $filename, $newname) == 0) {
  179. info(g_("moved '%s' to '%s'"), basename($filename), $newname);
  180. } else {
  181. error(g_('mkdir can be used to create directory'));
  182. }
  183. }
  184. }
  185. my @files;
  186. while (@ARGV) {
  187. $_ = shift(@ARGV);
  188. if (m/^-\?|--help$/) {
  189. usage();
  190. exit(0);
  191. } elsif (m/^-v|--version$/) {
  192. version();
  193. exit(0);
  194. } elsif (m/^-c|--create-dir$/) {
  195. $options{createdir} = 1;
  196. } elsif (m/^-s|--subdir$/) {
  197. $options{subdir} = 1;
  198. if (-d $ARGV[0]) {
  199. $options{destdir} = shift(@ARGV);
  200. }
  201. } elsif (m/^-o|--overwrite$/) {
  202. $options{overwrite} = 1;
  203. } elsif (m/^-k|--symlink$/) {
  204. $options{symlink} = 1;
  205. } elsif (m/^-a|--no-architecture$/) {
  206. $options{architecture} = 0;
  207. } elsif (m/^--$/) {
  208. push @files, @ARGV;
  209. last;
  210. } elsif (m/^-/) {
  211. usageerr(g_("unknown option '%s'"), $_);
  212. } else {
  213. push @files, $_;
  214. }
  215. }
  216. @files or usageerr(g_('need at least a filename'));
  217. foreach my $file (@files) {
  218. move($file);
  219. }
  220. 0;