From d4d3484ac88ca3953fef3cf2c0464cdc776b6574 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 16 May 1996 00:01:21 +0100 Subject: [PATCH] dpkg (1.2.0); priority=MEDIUM * dselect can sort packages by available and installed states, and display their version numbers. (Use O, o and V.) * Hold is properly integrated as a real `wanted state', rather than a separate flag. * Epochs in version numbers implemented, using the syntax :-. (Epoch not usually displayed.) * dselect disk method is architecture-independent (uses dpkg's installation architecture, and looks in the right part of the tree). * dselect disk method doesn't try to satisfy the predependencies of packages which are on hold. * Fixed conflict-related assertion failure. (Bug#2784.) * conffiles do not cause file conflicts if the conflicting package is in the `configuration only' state. (Bug#2720.) * Fixed messages where available version number was reported as installed version in conflict and dependency messages. (Bug#2654, Bug#2974.) * New format .deb files are default even for a.out compiles (but a.out version of dpkg is in old format). * Characters @:= (at colon equals) in package names now strictly forbidden everywhere (_ is still allowed in existing packages). * New dpkg --print-installation-architecture option prints installation architecture (compiled in), rather than build architecture (determined from gcc -print-libgcc-file-name). * Version messages show whether compiled a.out or ELF (i386 only). * Fixed missing space in version syntax error messages. * Manpage dpkg.8 installed with warning about inaccuracy. * Guidelines don't say to stop and restart daemons in runlevels 2345; instead they say to start in 2345 and stop in 016. * Guidelines and version messages say just Debian Linux. * Guidelines typo fix `"stop2' => `"stop"'. (Bug#2867.) * doc/Makefile.in clean properly deletes various guidelines.info* files. -- Ian Jackson Thu, 16 May 1996 00:01:21 +0100 --- TODO | 2 + acconfig.h | 3 + config.h.in | 6 + configure | 179 ++---- configure.in | 62 +- debian.Changelog | 40 ++ debian.buildscript | 23 + debian.changestemplate | 17 + debian.control | 2 +- debian.controlaout | 2 +- debian.mkchanges | 36 ++ debian.rules | 15 +- doc/Makefile.in | 2 +- doc/guidelines.info-1 | 1047 ------------------------------- doc/guidelines.info-2 | 744 ---------------------- doc/guidelines.texi | 43 +- doc/guidelines.texi.beforeeric | 1056 -------------------------------- doc/guidelines.texi.rej | 33 - dpkg-deb/build.c | 10 +- dpkg-deb/main.c | 8 +- dselect/helpmsgs.src | 28 +- dselect/main.cc | 10 +- dselect/methparse.cc | 3 +- dselect/pkgcmds.cc | 86 ++- dselect/pkgdepcon.cc | 24 +- dselect/pkgdisplay.cc | 107 +++- dselect/pkgkeys.cc | 207 ++++--- dselect/pkglist.cc | 177 +++++- dselect/pkglist.h | 45 +- dselect/pkgsublist.cc | 12 +- dselect/pkgtop.cc | 90 ++- include/dpkg-db.h | 43 +- include/dpkg.h | 5 +- lib/compat.c | 44 ++ lib/database.c | 15 +- lib/dump.c | 27 +- lib/fields.c | 70 ++- lib/parse.c | 78 +-- lib/parsedump.h | 6 +- lib/parsehelp.c | 83 ++- lib/sta00630 | Bin 0 -> 167936 bytes lib/sta11978 | Bin 0 -> 77824 bytes lib/varbuf.c | 16 + lib/vercmp.c | 16 +- main/archives.c | 142 +++-- main/cleanup.c | 28 +- main/configure.c | 4 +- main/depcon.c | 72 +-- main/dpkg.8 | 619 ++++++++++++++++++- main/dpkg.8-null | 20 + main/dpkg.8-vuori | 588 ------------------ main/enquiry.c | 18 +- main/errors.c | 2 +- main/help.c | 8 +- main/main.c | 15 +- main/main.h | 8 +- main/packages.c | 8 +- main/processarc.c | 54 +- main/remove.c | 6 +- methods/disk.setup | 14 +- split/main.c | 14 +- version.h | 2 +- 62 files changed, 1939 insertions(+), 4205 deletions(-) create mode 100644 debian.buildscript create mode 100644 debian.changestemplate create mode 100644 debian.mkchanges delete mode 100644 doc/guidelines.info-1 delete mode 100644 doc/guidelines.info-2 delete mode 100644 doc/guidelines.texi.beforeeric delete mode 100644 doc/guidelines.texi.rej create mode 100644 lib/sta00630 create mode 100644 lib/sta11978 create mode 100644 main/dpkg.8-null delete mode 100644 main/dpkg.8-vuori diff --git a/TODO b/TODO index 47165981..0a10a44b 100644 --- a/TODO +++ b/TODO @@ -24,6 +24,8 @@ bugs that need to be fixed quickly * remove old docs from /usr/doc/dpkg. other stuff unlikely to get done soon + * provide way for package to declare ownership of files for dpkg -S + and -L without having dpkg act on this * md5sum component in new .deb files * version number comparison option * diversions list as control archive entry diff --git a/acconfig.h b/acconfig.h index 0dae8ac0..5efaeeac 100644 --- a/acconfig.h +++ b/acconfig.h @@ -29,3 +29,6 @@ /* Set this to 1 to build new archives by default. */ #define BUILDOLDPKGFORMAT 0 + +/* Set this string to append something to the version number. */ +#define ARCHBINFMT "" diff --git a/config.h.in b/config.h.in index ad44f3f9..92b42a7e 100644 --- a/config.h.in +++ b/config.h.in @@ -55,6 +55,9 @@ /* Set this to 1 to build new archives by default. */ #define BUILDOLDPKGFORMAT 0 +/* Set this string to append something to the version number. */ +#define ARCHBINFMT "" + /* The number of bytes in a unsigned int. */ #undef SIZEOF_UNSIGNED_INT @@ -79,6 +82,9 @@ /* Define if you have the unsetenv function. */ #undef HAVE_UNSETENV +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + /* Define if you have the header file. */ #undef HAVE_SYS_CDEFS_H diff --git a/configure b/configure index 36f526a1..fd38b74d 100755 --- a/configure +++ b/configure @@ -18,8 +18,6 @@ ac_help="$ac_help --with-newdeb make dpkg-deb default to new archives" ac_help="$ac_help --with-olddeb make dpkg-deb default to old archives" -ac_help="$ac_help - --with-newdeb make dpkg-deb default to new archives" # Initialize some variables set by options. # The variables have the same names as the options, with @@ -563,6 +561,7 @@ else fi +dpkg_archset='' # Check whether --with-arch or --without-arch was given. withval="$with_arch" if test -n "$withval"; then @@ -570,10 +569,7 @@ if test -n "$withval"; then if test "x$with_arch" = x; then { echo "configure: error: --with-arch requires an architecture name" 1>&2; exit 1; } fi - cat >> confdefs.h <&6 - cat >> confdefs.h <&6 fi fi - -# Check whether --with-newdeb or --without-newdeb was given. -withval="$with_newdeb" -if test -n "$withval"; then - - cat >> confdefs.h <<\EOF -#define BUILDOLDPKGFORMAT 0 +if test "x$dpkg_archset" != x +then + cat >> confdefs.h <> confdefs.h <<\EOF -#define BUILDOLDPKGFORMAT 1 +if test "x${dpkg_archset}" = xi386; then + echo $ac_n "checking for i386 system/binary format""... $ac_c" 1>&6 + dpkg_libgcc="`$CC --print-libgcc-file-name 2>/dev/null`" + case "$dpkg_libgcc" in + *-linux*) + if ar p "$dpkg_libgcc" __main.o 2>/dev/null | file - 2>/dev/null | grep ELF >/dev/null; then + echo "$ac_t""Linux ELF" 1>&6 + dpkg_cc_binfmt=elf + else + echo "$ac_t""Linux a.out" 1>&6 + dpkg_cc_binfmt=a.out + fi + cat >> confdefs.h <&6 -if eval "test \"`echo '$''{'ac_cv_path_pathccompiler'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - case "$pathccompiler" in - /*) - ac_cv_path_pathccompiler="$pathccompiler" # Let the user override the test with a path. ;; *) - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_path_pathccompiler="$ac_dir/$ac_word" - break - fi - done - IFS="$ac_save_ifs" + echo "$ac_t""non-Linux" 1>&6 ;; -esac -fi -pathccompiler="$ac_cv_path_pathccompiler" -if test -n "$pathccompiler"; then - echo "$ac_t""$pathccompiler" 1>&6 -else - echo "$ac_t""no" 1>&6 + esac fi - ;; - esac - echo $ac_n "checking .deb format to build by default""... $ac_c" 1>&6 - if file "$pathccompiler" 2>/dev/null | grep ELF >/dev/null 2>&1; then - echo "$ac_t""new (C compiler looks like ELF)" 1>&6 - cat >> confdefs.h <<\EOF +# Check whether --with-newdeb or --without-newdeb was given. +withval="$with_newdeb" +if test -n "$withval"; then + cat >> confdefs.h <<\EOF #define BUILDOLDPKGFORMAT 0 EOF - else - echo "$ac_t""old (C compiler not ELF)" 1>&6 - cat >> confdefs.h <<\EOF -#define BUILDOLDPKGFORMAT 1 -EOF - - fi - -fi - fi - -# Check whether --with-newdeb or --without-newdeb was given. -withval="$with_newdeb" +# Check whether --with-olddeb or --without-olddeb was given. +withval="$with_olddeb" if test -n "$withval"; then cat >> confdefs.h <<\EOF -#define BUILDOLDPKGFORMAT 0 +#define BUILDOLDPKGFORMAT 1 EOF fi - echo $ac_n "checking for /usr/bin/perl""... $ac_c" 1>&6 if test -f /usr/bin/perl then @@ -770,7 +722,7 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error @@ -784,7 +736,7 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error @@ -818,7 +770,7 @@ else ac_cv_c_cross=yes else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < #include @@ -861,7 +813,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -879,7 +831,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -900,7 +852,7 @@ if test "$cross_compiling" = yes; then ac_cv_header_stdc=no else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -1033,7 +985,7 @@ if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1064,7 +1016,7 @@ if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1095,7 +1047,7 @@ if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1126,7 +1078,7 @@ if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < conftest.$ac_ext < #include @@ -1314,7 +1266,7 @@ if eval $ac_compile; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include @@ -1343,7 +1295,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext < main() @@ -1416,7 +1368,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() @@ -1442,14 +1394,14 @@ cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 else cat > conftest.$ac_ext < EOF @@ -1535,7 +1487,7 @@ if eval "test \"`echo '$''{'ac_cv_func_sysinfo'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 echo $ac_n "checking __NR_sysinfo""... $ac_c" 1>&6 cat > conftest.$ac_ext < @@ -1622,7 +1574,7 @@ fi else cat > conftest.$ac_ext < int main() { return 0; } @@ -1659,7 +1611,7 @@ fi else cat > conftest.$ac_ext < @@ -1702,7 +1654,7 @@ EOF else cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < @@ -1955,7 +1907,7 @@ else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wwrite-strings -Werror" cat > conftest.$ac_ext < @@ -2002,7 +1954,7 @@ else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wpointer-arith -Werror" cat > conftest.$ac_ext < @@ -2049,7 +2001,7 @@ else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wimplicit -Wnested-externs -Werror" cat > conftest.$ac_ext < @@ -2197,7 +2149,6 @@ s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@CC@%$CC%g s%@CXX@%$CXX%g -s%@pathccompiler@%$pathccompiler%g s%@perlpath@%$perlpath%g s%@CPP@%$CPP%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g diff --git a/configure.in b/configure.in index 0fe0f9ee..ecdb8ab7 100644 --- a/configure.in +++ b/configure.in @@ -8,13 +8,14 @@ AC_PREFIX_DEFAULT(/usr) AC_PROG_CC AC_PROG_CXX +dpkg_archset='' AC_ARG_WITH(arch, [ --with-arch=value set/override (Debian) architecture value], [ if test "x$with_arch" = x; then AC_MSG_ERROR(--with-arch requires an architecture name) fi - AC_DEFINE_UNQUOTED(ARCHITECTURE, "${with_arch}") + dpkg_archset="${with_arch}" ],[ AC_MSG_CHECKING(system architecture) dpkg_archwhy='' @@ -52,45 +53,42 @@ changequote([, ])dnl ]) if test "x$dpkg_cv_arch" != x; then AC_MSG_RESULT("$dpkg_cv_arch$dpkg_archwhy") - AC_DEFINE_UNQUOTED(ARCHITECTURE, "${dpkg_cv_arch}") + dpkg_archset="${dpkg_cv_arch}" else AC_MSG_RESULT("failed$dpkg_archwhy") fi ]) - -AC_ARG_WITH(newdeb, -[ --with-newdeb make dpkg-deb default to new archives], -[ - AC_DEFINE(BUILDOLDPKGFORMAT, 0) -],[ - AC_ARG_WITH(olddeb, -[ --with-olddeb make dpkg-deb default to old archives], -[ - AC_DEFINE(BUILDOLDPKGFORMAT, 1) -], -[ - case "$CC" in - /*) - pathccompiler="$CC" - ;; +if test "x$dpkg_archset" != x +then + AC_DEFINE_UNQUOTED(ARCHITECTURE, "${dpkg_cv_arch}") +fi + +if test "x${dpkg_archset}" = xi386; then + AC_MSG_CHECKING(for i386 system/binary format) + dpkg_libgcc="`$CC --print-libgcc-file-name 2>/dev/null`" + case "$dpkg_libgcc" in + *-linux*) + if ar p "$dpkg_libgcc" __main.o 2>/dev/null | file - 2>/dev/null | grep ELF >/dev/null; then + AC_MSG_RESULT(Linux ELF) + dpkg_cc_binfmt=elf + else + AC_MSG_RESULT(Linux a.out) + dpkg_cc_binfmt=a.out + fi + AC_DEFINE_UNQUOTED(ARCHBINFMT, " $dpkg_cc_binfmt") + ;; *) - AC_PATH_PROG(pathccompiler,"$CC") - ;; - esac - AC_MSG_CHECKING(.deb format to build by default) - if file "$pathccompiler" 2>/dev/null | grep ELF >/dev/null 2>&1; then - AC_MSG_RESULT([new (C compiler looks like ELF)]) - AC_DEFINE(BUILDOLDPKGFORMAT, 0) - else - AC_MSG_RESULT([old (C compiler not ELF)]) - AC_DEFINE(BUILDOLDPKGFORMAT, 1) - fi -])]) + AC_MSG_RESULT(non-Linux) + ;; + esac +fi AC_ARG_WITH(newdeb, [ --with-newdeb make dpkg-deb default to new archives], [AC_DEFINE(BUILDOLDPKGFORMAT, 0)]) - +AC_ARG_WITH(olddeb, +[ --with-olddeb make dpkg-deb default to old archives], +[AC_DEFINE(BUILDOLDPKGFORMAT, 1)]) AC_MSG_CHECKING(for /usr/bin/perl) if test -f /usr/bin/perl @@ -116,7 +114,7 @@ AC_C_CONST AC_C_BIGENDIAN AC_CHECK_SIZEOF(unsigned long) AC_CHECK_SIZEOF(unsigned int) -AC_CHECK_FUNCS(unsetenv alphasort scandir strerror strsignal strtoul) +AC_CHECK_FUNCS(unsetenv alphasort scandir strerror strsignal strtoul vsnprintf) AC_CHECK_HEADERS(sys/cdefs.h) AC_CHECK_FUNC(sysinfo, diff --git a/debian.Changelog b/debian.Changelog index 4985617e..2835742e 100644 --- a/debian.Changelog +++ b/debian.Changelog @@ -1,3 +1,43 @@ +dpkg (1.2.0); priority=MEDIUM + + * dselect can sort packages by available and installed states, and + display their version numbers. (Use O, o and V.) + * Hold is properly integrated as a real `wanted state', rather than + a separate flag. + * Epochs in version numbers implemented, using the syntax + :-. (Epoch not usually displayed.) + * dselect disk method is architecture-independent (uses dpkg's + installation architecture, and looks in the right part of the tree). + + * dselect disk method doesn't try to satisfy the predependencies of + packages which are on hold. + * Fixed conflict-related assertion failure. (Bug#2784.) + * conffiles do not cause file conflicts if the conflicting package + is in the `configuration only' state. (Bug#2720.) + * Fixed messages where available version number was reported as installed + version in conflict and dependency messages. (Bug#2654, Bug#2974.) + + * New format .deb files are default even for a.out compiles (but + a.out version of dpkg is in old format). + * Characters @:= (at colon equals) in package names now strictly + forbidden everywhere (_ is still allowed in existing packages). + * New dpkg --print-installation-architecture option prints installation + architecture (compiled in), rather than build architecture (determined + from gcc -print-libgcc-file-name). + + * Version messages show whether compiled a.out or ELF (i386 only). + * Fixed missing space in version syntax error messages. + * Manpage dpkg.8 installed with warning about inaccuracy. + + * Guidelines don't say to stop and restart daemons in runlevels 2345; + instead they say to start in 2345 and stop in 016. + * Guidelines and version messages say just Debian Linux. + * Guidelines typo fix `"stop2' => `"stop"'. (Bug#2867.) + + * doc/Makefile.in clean properly deletes various guidelines.info* files. + + -- Ian Jackson Thu, 16 May 1996 00:01:21 +0100 + dpkg (1.1.6); priority=MEDIUM * Check virtual dependencies when removing (ouch! - thanks SDE.) diff --git a/debian.buildscript b/debian.buildscript new file mode 100644 index 00000000..6a85cd77 --- /dev/null +++ b/debian.buildscript @@ -0,0 +1,23 @@ +#!/bin/sh +set -e -x +really ./debian.rules clean +./debian.rules diff source + +./debian.rules build +really ./debian.rules binary + +curd="`pwd`" +newd="`basename \"$curd\"`"elf +rm -rf ../"$newd" +cp -dpR . ../"$newd" + +PATH=/usr/i486-linuxaout/bin:$PATH +export PATH + +really ./debian.rules clean +./debian.rules build +really ./debian.rules binary + +version=`sed -n 's/^version=//p' debian.rules` +perl debian.mkchanges "$version" dpkg-$version.`dpkg --print-architecture`.changes diff --git a/debian.changestemplate b/debian.changestemplate new file mode 100644 index 00000000..a07b1e1c --- /dev/null +++ b/debian.changestemplate @@ -0,0 +1,17 @@ +Date: =d +Format: 1.5 +Distribution: unstable +Source: dpkg +Binary: dpkg +Architecture: source =a +Version: =v +Maintainer: Ian Jackson +Description: + dpkg: Package maintenance system for Debian Linux +Changes:=c +Files: + =f:dpkg-=v.tar.gz base required + =f:dpkg-=velf.=a.deb base required + =f:dpkg-=v.=a.deb byhand - + =f:dpkg-=velf.=a.nondebbin.tar.gz byhand - + =f:dpkg-=v.=a.nondebbin.tar.gz byhand - diff --git a/debian.control b/debian.control index 19ffe299..f38dbd9f 100644 --- a/debian.control +++ b/debian.control @@ -6,7 +6,7 @@ Pre-Depends: libc5=, ncurses3.0 Conflicts: dpkgname Replaces: dpkgname Maintainer: Ian Jackson -Description: Package maintenance system for Debian GNU/Linux +Description: Package maintenance system for Debian Linux This package contains the programs which handle the installation and removal of packages on your system. . diff --git a/debian.controlaout b/debian.controlaout index d2827f97..89447013 100644 --- a/debian.controlaout +++ b/debian.controlaout @@ -6,7 +6,7 @@ Conflicts: dpkgname Replaces: dpkgname Pre-Depends: libc4 | libc Maintainer: Ian Jackson -Description: Package maintenance system for Debian GNU/Linux +Description: Package maintenance system for Debian Linux This package contains the programs which handle the installation and removal of packages on your system. . diff --git a/debian.mkchanges b/debian.mkchanges new file mode 100644 index 00000000..82b57e17 --- /dev/null +++ b/debian.mkchanges @@ -0,0 +1,36 @@ +#!/usr/bin/perl +# Usage: +# perl debian.mkchanges thing.changes + +$x=time; sub z { $_[1]+$_[2]*60; }; @l=localtime($x); $od=1440; +$d=&z(@l)-&z(gmtime($x)); $d+=$od; $d%=$od; $s=$d>$od/2?($d=$od-$d,'-'):'+'; +$date=sprintf("%s, %d %s %d %02d:%02d:%02d %s%02d%02d", + (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$l[6]], $l[3], + (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$l[4]], $l[5]+1900, + $l[2],$l[1],$l[0], $s,$d/60,$d%60); + +($version)=@ARGV; +chop($arch=`dpkg --print-architecture`); + +open(Z,"debian.Changelog"); +while() { $changes.=$_; last if m/^ --/; } +close(Z); $changes =~ s/^/ /g; $changes =~ s/^/\n/; $changes =~ s/\n$//; + +chdir(".."); + +while () { + s/=a/$arch/g; + s/=v/$version/g; + if (m/^ =f:(\S+) (\S+) (\S+)$/) { + ($file,$sec,$pri)=($1,$2,$3); + $!=0; chop($md5sum=`md5sum <$file`); $? && die "$file: $? $!"; + $!=0; $size=`ls -l $file`; $? && die "$file: $? $!"; + $size =~ m/^\S+\s+\d+\s+\S+\s+\S+\s+(\d+)\s/ || die "$file: `$size'"; + $size= $1; + $_= " $md5sum $size $sec $pri $file\n"; + } else { + s/=c/$changes/ || s/=d/$date/g; + } + print || die $!; +} +close(STDOUT) || die $!; diff --git a/debian.rules b/debian.rules index 4b671c06..a1c00dd1 100755 --- a/debian.rules +++ b/debian.rules @@ -1,7 +1,7 @@ #!/usr/bin/make -f package=dpkg -version=1.1.6 +version=1.2.0 archi=$(shell dpkg --print-architecture) DIR:=$(shell pwd) @@ -52,16 +52,17 @@ binary: chown -R root.root debian-tmp chmod -R g-ws debian-tmp cd debian-tmp && \ - tar cf ../../$(package)-$(version).nondebbin.tar usr var && \ - gzip -9vf ../../$(package)-$(version).nondebbin.tar + tar cf ../../$(package)-$(version).$(archi).nondebbin.tar usr var && \ + gzip -9vf ../../$(package)-$(version).$(archi).nondebbin.tar mv debian-tmp/usr/bin/dpkg-deb{,.dist} rm debian-tmp/var/lib/dpkg/{status,available} - dpkg --build debian-tmp - if file main/dpkg | grep -q ELF; then \ + set -e; if file main/dpkg | grep -q ELF; then \ + dpkg-deb --build --new debian-tmp ; \ mv debian-tmp.deb ../dpkg-$(version)elf.$(archi).deb ; \ - mv ../dpkg-$(version).nondebbin.tar.gz \ - ../dpkg-$(version)elf.nondebbin.tar.gz ; \ + mv ../dpkg-$(version).$(archi).nondebbin.tar.gz \ + ../dpkg-$(version)elf.$(archi).nondebbin.tar.gz ; \ else \ + dpkg-deb --build --old debian-tmp ; \ mv debian-tmp.deb ../dpkg-$(version).$(archi).deb ; \ fi diff --git a/doc/Makefile.in b/doc/Makefile.in index 9b9724c1..e09b163c 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -66,7 +66,7 @@ database-structure.monops: database-structure.ps clean: rm -f database-structure.ps database-structure.monops ps rm -f *.{aux,cp,dvi,fn,ky,log,pg,toc,tp,vr} - rm -f guidelines.info + rm -f guidelines.info* distclean: rm -f Makefile *.orig *~ *.~* ./#*# diff --git a/doc/guidelines.info-1 b/doc/guidelines.info-1 deleted file mode 100644 index c69a3348..00000000 --- a/doc/guidelines.info-1 +++ /dev/null @@ -1,1047 +0,0 @@ -This is Info file guidelines.info, produced by Makeinfo-1.63 from the -input file ./guidelines.texi. - -START-INFO-DIR-ENTRY -* Guidelines: (guidelines). How to make Debian packages. -END-INFO-DIR-ENTRY - - -File: guidelines.info, Node: Top, Next: Additional Information, Prev: (dir), Up: (dir) - -Debian GNU/Linux Packaging Guidelines -************************************* - - This file documents the steps that must be taken in the preparation -of a Debian GNU/Linux package. All submissions to be included in the -distribution proper and all packages to be considered for `contrib' or -`non-free' availability *must* conform to the guidelines and standards -described in this document or they cannot be included or made available -at the archive with the distribution. - - Please read the Guidelines carefully. If you have comments or -questions, please contact `debian-devel@pixar.com'. If you are -planning on going further than just contributing a package (i.e., if -you plan to maintain it for an extended period of time or if you are -generally interested in becoming more involved in the Project), you -should join the `debian-devel' mailing list. For more details, read -`info/mailing-lists.txt', available at any Debian GNU/Linux archive. - - (This file was last updated on 26th January 1996. Please check the -most recent `dpkg' package at any Debian GNU/Linux archive for a -potentially more up to date copy.) - -* Menu: - -* Additional Information:: Where other info is to be found. -* Package Copyright:: A few words about the importance of - understanding the package copyright. -* Package Content:: Requirements for the package content. -* Source Package:: Creating the source package. -* Binary Package:: Creating the binary package. -* Control Files:: The binary package control files. -* Appendix:: More specific details about some aspects. - - -File: guidelines.info, Node: Additional Information, Next: Package Copyright, Prev: Top, Up: Top - -Additional Information -********************** - - These Guidelines are intended to be fairly general. More specific -information is available about certain aspects of building packages, -such as how to use the features of Init under Debian GNU/Linux and how -to interact with some more technical details of dpkg's operation. This -information can be found in the directory `doc/package-developer' at -any Debian GNU/Linux archive. At the time of this writing, the -following documents are available: - -`virtual-package-names-list.text' - The list of virtual package names currently in use, together with - the procedure for getting new virtual package names allocated. - -`auto-deconfiguration.txt' - How dpkg can sometimes automatically deconfigure packages in order - to do bulk installations smoothly. - -`dpkg-essential-flag.txt' - How to tell dpkg a package is essential and should not be removed. - (This is for the use of base system packages only.) - -`dpkg-disappear-replace.txt' - What happens when a package appears to have been completely - replaced. - - In the future, we hope also to make available: - -`copyright.txt' - How to choose a good copyright notice to attach to new programs. - -`version-ordering.txt' - The algorithm with which packages' version numbers are compared. - - Also, you should download the sample files and the sample package -(GNU Hello) available in `standards/samples'. You may use any of this -material as a starting point for new packages. The following sample -files, incidentally, are available: - - * debian.README - - * debian.control - - * debian.postinst - - * debian.postrm - - * debian.rules - - Some more detailed information about certain topics is available in -the appendix to this document (*note Appendix::.). - - -File: guidelines.info, Node: Package Copyright, Next: Package Content, Prev: Additional Information, Up: Top - -Package Copyright -***************** - - Please study the copyright of your submission *carefully* and -*understand it* before proceeding! If you have doubts or questions, -please ask! - - In order to understand how we classify and distribute certain -packages, it is important to understand the distinction between being -freely available and being freely redistributable. - - Being "freely available", quite simply, means that the software can -be made available freely, at least for non-commercial purposes and in -its original, unmodified form. This includes packages made available -freely that have restrictions on non-commercial use, redistribution of -modifications, etc. Being freely available, therefore, has nothing to -do with being able to modify and redistribute the software. It only -means that you can get a copy of the software without having to pay -(and it does not necessarily mean that you can *use* the software -without having to pay--shareware is an example of freely available -software). - - "freely redistributable", while generally being freely available, -goes beyond just being freely available. Freely redistributable means -that that the software, in addition to being able to be made available -freely, must be able to be freely modified and redistributed without -restriction. - - All submissions to be included in the distribution proper *must* be -freely redistributable. - - In addition to the distribution, the Project maintains two separate -archives of software packages with the distribution: the `contrib' -archive and the `non-free' archive. - - `contrib' is an archive of user-contributed packages that are not -maintained by the Project, packages that were once maintained by the -Project but that are no longer actively maintained, and packages that -are maintained by the Project but that are not yet considered ready for -inclusion in the distribution proper (i.e., ALPHA and BETA packages). -As above, all submissions for inclusion in the `contrib' archive *must* -be freely redistributable. - - `non-free' is an archive of packages with either restrictive or -unclear terms of copying or modification. If a package has *any* -restrictions on modification or redistribution, it can not be included -in the distribution or `contrib' archive. It can only be included in -the `non-free' archive, and then only if it is freely available. - - In summary, in order to be included in the distribution proper or the -`contrib' archive, a package must be *freely redistributable*. Anyone -must be able to make copies of it, modify it, redistribute it with -their modifications in place, include it on a CD-ROM, or generally sell -it. To be included in the `non-free' archive, a package may have -restrictions, as long as the package remains *freely available*. We -must be available to make it available freely at the archive, and anyone -must be able to make copies of it and use it for at least -non-commercial, personal purposes. Software that will typically be -included in `non-free' are software that does not allow commercial -distribution, software that does not allow modification or -redistribution of modifications, commercial "demos", and "shareware". - - When in doubt, send mail to `iwj10@cus.cam.ac.uk' and -`imurdock@debian.org'. Be prepared to provide us with the copyright -statement. Software covered by the GPL, public domain software and -BSD-like copyrights are safe; be wary of the phrases "commercial use -prohibited" and "distribution restricted". - - Every package submission *must* be accompanied by verbatim copy of -its copyright (with the exceptions of public domain packages and those -covered by the UCB BSD licence or the GNU GPL or LGPL; in these cases -simply indicate which is appropriate). This information must be -included in a file installed to the directory `/usr/doc/copyright'. -See below for details. - - -File: guidelines.info, Node: Package Content, Next: Source Package, Prev: Package Copyright, Up: Top - -Package Content -*************** - - The following requirements apply equally to both the binary and -source packages. In either case, when files have been installed, they -must conform to the requirements described in this section. - - The primary rule in Debian GNU/Linux is to follow the Linux "File -System Standard" ("FSSTND"). The location of installed files *must* -comply *fully* with the FSSTND. The latest version of this document -can be found alongside the Guidelines or at `tsx-11.mit.edu' in -`/pub/linux/docs/linux-standards/fsstnd'. Specific questions about -following the standard should be addressed to Daniel Quinlan, the -FSSTND coordinator, at `quinlan@yggdrasil.com'. - - In addition to the FSSTND, all Debian GNU/Linux packages must follow -the guidelines below. - - * Directories should be mode 755 or (for group-writability) mode - 2775, with the exception of special "system" directories that need - to be another mode. The ownership of the directory should be - consistent with its mode--if a directory is mode 2775, it should - be owned by the group that needs write access to it, of course. - Use common sense in assigning permissions and ownerships to - directories, and make sure that what is done is secure if it is - "non-standard". - - * Normal binaries should be mode 755 and owned by `root.root'. If - there is a good reason to use a different mode or ownership, you - may do so, but you must try to be as consistent as possible with - the rest of the system. If you need to use a different mode or - ownership, please discuss it with `imurdock@debian.org'. - - * Setuid binaries should normally be mode 4755 (not 4711!) and, of - course, owned by the appropriate user. - - * Setgid binaries should normally be mode 2755 (not 2711!) and, of - course, owned by the appropriate group. - - * Library files should generally be mode 644 and owned by - `root.root'; shared libraries should be mode 755. If the package - requires different permissions or ownerships to function - correctly, they should be used instead. - - * Manual pages should be mode 644 and owned by `root.root'. The - `nroff' source must be installed. You should *not* install a - preformatted "cat page", and you should only use sections 1 to - 9--see the FSSTND for more details. If no manual page is - available for a particular program, utility or function and this - is reported as a bug on debian-bugs, a symbolic link from the - requested manual page to the `undocumented'(7) manual page should - be provided. This symbolic link can be created from `debian.rules' - like this: - - ln -s ../man7/undocumented.7 debian-tmp/usr/man/man[1-9]/the_requested_manpage.[1-9] - - Do not close the bug report until a proper manpage is available. - You may forward the complaint to the upstream maintainers, and - mark the bug as forwarded in the Debian bug tracking system. The - GNU Project do not in general consider the lack of a manpage to be - a bug, but we do - if they tell you to go away leave the bug open - anyway. - - * Info documents should be mode 644, owned by `root.root', and - compressed with `gzip -9' when installed. The package must call - `install-info' to update the Info `dir' file. This should be done - in the post-installation script (`postinst'), like this: - - install-info --quiet /usr/info/foobar.info - - The entries should be removed by the pre-removal script (`prerm'), - like this: - - install-info --quiet --remove /usr/info/foobar.info - - It is also a good idea to specify a section for the Info `dir' - entry. This is done with the `--section' switch. To determine - which section to use, you should use look at `/usr/info/dir' on - your system and choose the most relevant (or create a new section - if none of the current sections are relevant). - - If `install-info' cannot find a description entry in the Info file - you will have to supply one. See `install-info'(8) for details. - - * If a package contains any shared libraries you will have to invoke - `ldconfig' in both the `postinst' and `prerm' scripts to correctly - update the library links. See `ldconfig'(8) for details. - - * Any additional documentation that comes with the package can be - installed at the discretion of the package maintainer. Text - documentation should be mode 644, owned by `root.root', installed - to `/usr/doc', and compressed with `gzip -9' unless it is small. - - If a subdirectory of `/usr/doc' is warranted, please do create one. - Please do not install DVI, PostScript, or large textual - documentation in the same package; upload such documentation as a - separate package (installing its files in `/usr/doc') so that it - can be made available with the distribution. If a user has the - need for the documentation, they can easily get it from the - archive, CD-ROM, etc., but it should not take up disk space on the - machines of the user who do not need or want it installed. - - * Create a file named `/usr/doc/copyright/' which gives - details of the authorship and copyright of the package. If the - package is distributed under the GNU General Public Licence, the - GNU Library General Public Licence or the Regents of the - University of California at Berkeley (BSD) licence, please say so - instead of including a copy of the licence. The files `BSD', - `GPL', and `LGPL' will be available in the `/usr/doc/copyright' - directory for you to refer to. `/usr/doc/copyright/' - should not be compressed. - - *All* authorship and copyright information from the original source - package must be included in the `/usr/doc/copyright/' - file. - - * Any example files (for example, sample configuration files) should - be placed in the directory `/usr/doc/examples'. If the file is - normally a hidden file, such as `.emacs', then please call it - `dot.emacs', to avoid confusion. Again, you may create a - subdirectory if it is needed. - - * All symbolic links should be relative, not absolute. Absolute - links, in general, cause problems when a file system is not - mounted where it "normally" resides (for example, when mounted via - NFS). In certain cases, however, relative links may also cause - similar problems. I have generally made links into `/etc' and - `/var' absolute and all other links relative. There may be other - cases in which absolute links are necessary. - - Therefore, in the `Makefile' or `debian.rules', do not do: - install: all - [...] - ln -fs /usr/bin/gcc /usr/bin/cc - [...] - Instead, do: - ln -fs gcc /usr/bin/cc - or - ( cd /usr/bin ; ln -fs gcc cc ) - - Please do not create hard links in the manual page directories. In - these cases, you should use relative symbolic links or files that - `.so' (roff for `source') others instead. - - * All command scripts should have a `#!' line naming the shell to be - used to interpret them. - - * In the case of Perl scripts this should be `#!/usr/bin/perl' or - sometimes `#!/bin/perl', as follows: if the script is a critical - one that may be called when the `/usr' partition is unmounted or - broken it should use `/bin/perl'. Otherwise (especially if the - script is not specifically targetted at Debian) it should use - Perl's standard location, `/usr/bin/perl'. - - * Generally the following compilation parameters should be used: - - CC = gcc - CFLAGS = -O2 -g -Wall # sane warning options vary between programs - LDFLAGS = # none (or -N, if appropriate; see below) - install -s (or strip) - - Note that all installed binaries should be stripped, either by - using the `-s' flag to `install', or by calling `strip' on the - binaries after they have been copied into the `debian-tmp' but - before the tree is made into a package. - - Make sure that you do not link with `-g', as this makes a.out - compilers produce huge statically linked binaries. The `-g' flag - is useful on compilation so that you have available a full set of - debugging symbols in your built source tree, in case anyone should - file a bug report involving (for example) a core dump. - - `-N' should only be used on binaries that are very small (less than - 8K with the `-N' option, roughly) and are not likely to have - multiple instances in memory. Do not use `-N' on daemons, no - matter how small they are. - - It is up to the package maintainer to decide what compilation - options are best for the package. Certain binaries (such as - computationally-intensive programs) may function better with - certain flags (`-O3', for example); feel free to use them. Please - use good judgment here. Don't add flags for the sake of adding - flags; only add flags if there is good reason to do so. - - * Please make sure that you use only released versions of shared - libraries to build your packages; otherwise other users will not - be able to run your binaries properly. Producing source packages - that depend on unreleased compilers is also usually a bad idea. - - * Logfiles should usually be named `/var/log/', or - `/var/log/.' if you have several logfiles. It - may be appropriate to create a directory. Make sure that any - logfiles are rotated occasionally so that they don't grow - indefinitely; the best way to do this is to use `savelog' from the - cron package in an `/etc/cron.daily', `/etc/cron.weekly' or - `/etc/cron.monthly' script. - - * Please check with the base system maintainer (Ian Murdock) before - using users or groups other than `root' and others specified in - this document. - - -File: guidelines.info, Node: Source Package, Next: Binary Package, Prev: Package Content, Up: Top - -Source Package -************** - - The source package should contain a file called `debian.rules' which -contains at least the following targets, to be invoked in the top level -directory: - - build - binary - clean - - `debian.rules' should start with - - #!/usr/bin/make -f - -and be executable. It is a good idea to arrange for it not to fail -obscurely when invoked in the wrong directory, for example by testing -for the existence of a file in the source directory. - - * The `build' target should perform all non-interactive configuration - and compilation of the package. If a package has an interactive - pre-build configuration routine, the source package should be built - *after* this has taken place. - - For some packages, notably ones where the same source tree is - compiled in different ways to produce two binary packages, the - `build' target does not make much sense. For these packages it is - good enough to provide two (or more) targets (`build-a' and - `build-b' or whatever) for each of the ways of building the - package, and a `build' target that does nothing. The `binary' - target will have to build the package in each of the possible ways - and make the binary package out of each. - - * The `binary' target of `debian.rules' should be all that is - necessary for the user to build the binary package. The binary - package should be created using `dpkg' and placed in the parent of - the top level directory. The next section describes how to - construct binary packages from the `binary' target. - - * The `clean' target should undo the effects of the `build' target - and the `binary' target, except that it should leave alone any - `../-.deb' file created by a run of `binary'. - - * Additional targets may exist in `debian.rules'. We recommend using - `source' and `diff' targets to build the Debianised source package - and the Debianisation context diff, respectively. These files - should be placed in `../foo-.tar.gz' and - `../foo-.diff.gz'. The `install' target, for installing - into a running system direct from the Debianised source tree, is - no longer required. The sample `debian.rules' provides `source' - and `diff' targets that should work with little or no alteration, - providing that the package-specific variables at the top of the - script have been properly defined. - - * If you need to edit a `Makefile' where `configure' scripts are - used, you should edit the `.in' files rather than editing the - `Makefile' directly. This allows the user to reconfigure the - package if necessary. You should *not* configure the package and - edit the generated `Makefile'! This makes it impossible for - someone else to later reconfigure the package. - - * Please document your changes to the source package so that future - package maintainers know what has been changed. To do this, - include a description of your changes in the `debian.README' - (which, as described above, should already contain authorship and - copyright information!) and include relevant information such as - your name, electronic mail address, date, etc. The - `debian.README' file should also document any `unusual' packages - which must be installed for this one to compile. - - * If changes to the source code are made that are applicable to Linux - systems or systems in general please try to get them included in - the upstream version of the package by supplying the upstream - authors with the changes in whatever form they prefer. - - If changes to the source code are made, please use a `define'. If - they are changes required to compile or function under Linux in - general, use `LINUX'. If it is a cosmetic or functional change, - use `DEBIAN'. - - * Create the source package using `tar', and use `gzip -9' to - compress it. Source packages should be named in the form - -.tar.gz--for example, `fileutils-3.9-3.tar.gz'. - - NB, here `' is the full Debian version number, in the - form `-' (see below), but the - tarfile should unpack into a directory named - `-' (again, see the section below on - version numbering). - - * Create the unified context diff against the original package using - `diff -uNr', and use `gzip -9' to compress it. Diffs should be - named in the form -.diff.gz--for example, - `fileutils-3.9-3.diff.gz'. - - Please note that the package and patch filenames do *not* need to -fit in MS-DOS 8+3. They will be made available under an alternative -8+3 name in the archive by the archive maintainer, using a symlink. - - -File: guidelines.info, Node: Binary Package, Next: Control Files, Prev: Source Package, Up: Top - -Binary Package -************** - - The `binary' target of the source package `debian.rules' file should -do the following (see the sample `debian.rules' for an implementation -that you are free to modify and use in your own packages, of course): - - * Create an empty directory in the top-level directory of the source - package (deleting it first, if necessary), and install the files - belonging to this package in that directory. For example, the - directory could be called `debian-tmp' and would probably contain - directories `debian-tmp/usr/bin', `debian-tmp/usr/lib', etc. - (`debian-tmp' is the name traditionally used, and it is used in - the sample `debian.rules' file, so we will use that name in the - Guidelines.) - - * Make sure that all the files under `debian-tmp' have the correct - ownerships and permissions (*note Package Content::., for more - information about file locations, ownerships, and permissions.) - - * Create a subdirectory of `debian-tmp' called `DEBIAN'. This - directory contains the package control information, including at - the very least the master information file named `control'. The - next section describes the semantics and syntax of the files - required and allowed here. - - * Run `dpkg' to create the binary package, using something like - - dpkg --build debian-tmp - - This will create a file called `debian-tmp.deb', from the - `debian-tmp' directory. You should rename this file to - `../-.deb' after it is built. - - After the `binary' target has done all this, the - `-.deb' file in the parent directory is the - binary distribution. This file may be distributed and installed on - any Debian GNU/Linux system with `dpkg' in the same manner and - using the same methods as all packages are installed to the system. - - * If a single source package corresponds to several binary packages, - there should usually be a `debian.rules' file with a single - `binary' target that builds all the binary packages involved and - move all packages to the parent directory of that containing the - source package. - - In this case, you should choose binary package names which are - meant to make clear the close relationship between the binary - packages and which source package the binary packages came from - (for example, the `texinfo' source package build two binary - packages: `texidoc' and `texinfo'). You should place the - appropriate binary package name in the `Package' field of the - control file (not the source package name), and you should - consider whether the other binary packages that come from the same - source tree should be mentioned in the `Depends', `Recommends' or - `Suggests' fields. You should put the source package name in the - `Source' field. - - You should retain the source package version numbering in the - `Version' field, if possible--the version number should be the - same for the Debianised source tree and all the binary packages - generated from it. It is more important, though, that the version - numbers sort correctly. See below for details of version numbers. - - -File: guidelines.info, Node: Control Files, Next: Appendix, Prev: Binary Package, Up: Top - -Control Files -************* - - Each binary package contains, in addition to the files that comprise -the actual package, a set of text files that control how `dpkg' -installs, configures, upgrades, removes, etc. the package. These files -are called "control files". When creating the package, the control -files should placed in a directory called `DEBIAN', as described -earlier (*note Binary Package::., for further information). - - The control information files are: - -`control' - The master package control information file. - -`conffiles' - A list of package configuration files. - -`preinst' - The package pre-installation script. - -`postinst' - The package post-installation script. - -`prerm' - The package pre-removal script. - -`postrm' - The package post-removal script. - - Of these, only `control' is required. The various installation -scripts, and the configuration files list, will only be used if they are -present. - -* Menu: - -* control:: -* conffiles:: -* Installation and Removal Scripts:: -* Dependencies and Conflicts:: -* Package Classification Fields:: - - -File: guidelines.info, Node: control, Next: conffiles, Prev: Control Files, Up: Control Files - -control -======= - - The `control' file contains a number of fields. Each field begins -with a field name, such as `Package' or `Version' (case insensitive), -followed by a colon and optionally some spaces or tabs (a single space -is conventional). Then comes the body of the field, which may be -several lines long; each continuation line must start with at least one -space or tab. (These are the same rules as apply to RFC822 mail -headers.) Blank lines are not permitted in the control file. - - The required fields in the control file are the following: - -`Package' - The name of the package. - -`Description' - The description of the package. How to write an extended and more - usefull description field can be found in *note How to write the - Description control file field::.. - -`Maintainer' - The name and e-mail address of the maintainer of the package. - -`Version' - The version number in the format - `-'. - - Each field has a particular format and meaning for the package -installation tools. - - The value of `Package' should be the name of the package. Package -names must start with an alphanumeric, must be at least two characters, -and may contain only alphanumerics and the characters - + . (that is, -hyphen, plus, stop) (1). They are sort of case sensitive - please try -to get the case right first time. - - The `Maintainer' field should be in the form - - Joe J. Bloggs - -Note that this will not be useable as an email address if the name -given contains full stop characters, because of a silly restriction in -the Internet mail standards. If you want to use this as an email -address in a program you should check for full stops and change the -string to the form `jbloggs@foo.com (Joe J. Bloggs)' if you find any. - - The `Version' field should be the version number of the package. -For most packages which are not written specifically for Debian, this -should be in the form - - Version: - - -where `' is the original package version number in -whatever form the original package uses and `' -indicates which "debianisation" this is (this should usually be a plain -number or perhaps a two numbers separated by a full stop, and should be -incremented each time the package is changed or updated). - - Packages which are written specifically for Debian do not have a -debian_revision, and their version number should simply be version -(which should not contain any hyphens, to avoid confusion). - - There is an ordering imposed on version numbers, described in -`version-ordering.txt'. This ordering is designed to `do the right -thing' in most circumstances; if your package has an version number in -an unusual format you may need to reformat it somewhat to get the -ordering right. This is important because `dpkg' is (for example) -reluctant to downgrade packages. - - The optional fields in the control file are the following: - -`Depends' - The names of prerequisite packages. - -`Recommends' - The names of related, recommended packages. - -`Suggests' - The names of related, optional packages. - -`Conflicts' - The names of packages which conflict with this package. - -`Provides' - The names of virtual packages which this package provides. - -`Priority' - The `priority' of the package, as shown and used by `dselect'. - -`Section' - The `section' of the package, as shown and used by `dselect', and - used as a location for the package in the distribution. - -`Essential' - A boolean field used by the base packages. - -`Pre-Depends' - Used by base packages to ensure that (for example) shared - libraries are present before they are upgraded. This feature is - for expert use only. - -`Source' - Gives the name of the source package when several binary packages - are generated from a single source tree. - -See below for details of the semantics and syntax of these fields. -Most packages will need at least a `Depends' field. - - An example of a `control' file would be: - - Package: smail - Version: 3.1.29.1-13 - Maintainer: Ian Jackson - Recommends: pine | mailx | elm | emacs | mail-user-agent - Suggests: metamail - Depends: cron, libc5 - Conflicts: sendmail - Provides: mail-transport-agent - Description: Electronic mail transport system. - Smail is the recommended mail transport agent (MTA) for Debian. - . - An MTA is the innards of the mail system - it takes messages from - user-friendly mailer programs and arranges for them to be delivered - locally or passed on to other systems as required. - . - In order to make use of it you must have one or more user level - mailreader programs such as elm, pine, mailx or Emacs (which has Rmail - and VM as mailreaders) installed. If you wish to send messages other - than just to other users of your system you must also have appropriate - networking support, in the form of IP or UUCP. - - In this case, `mail-user-agent' is a virtual package representing -any user mailer program; the actual package names `pine' is quoted for -the reasons described in `dependency-ordering.txt', and the others -because older versions of those packages do not have the appropriate -`Provides' field. - - ---------- Footnotes ---------- - - (1) The characters @ : = % _ (at, colon, equals, percent and -underscore) used to be legal and are still accepted when found in a -package file, but may not be used in new packages - - -File: guidelines.info, Node: conffiles, Next: Installation and Removal Scripts, Prev: control, Up: Control Files - -conffiles -========= - - The contents of `conffiles' is simply a list of configuration files -in the package. When installing the package, `dpkg' uses an -intelligent method to update these files. This will ensure that -package-specific configuration files are not overwritten when a package -is upgraded, unless the user wishes the installation tools to do so. - - Typically, files listed in conffiles are package-specific -configuration files, which (according to the Linux Filesystem Standard) -are stored in `/etc'. For example, the `sendmail' package may contain -the file `/etc/sendmail.cf', which we do not wish to overwrite -automatically when the user upgrades the sendmail package. Only those -files listed in `DEBIAN/conffiles' will be updated intelligently when a -package is upgraded; all other files in the package will be overwritten -by the upgrade process. - - Configuration files which will be functional as shipped and will -probably need little or no local editing should simply be listed the -`conffiles' file; in this case you need read no further. - - For packages whose configuration files will need modification on -most systems there are two sensible approaches. Which one is chosen -depends on how hard the configuration problem is and how much time the -package maintainer has available. - - One option is for you to ship a minimal `best-effort' file in -`/etc', and list the file in `conffiles'. This will mean that the user -will have to go and edit the file themselves to get the package to work -properly, of course. The next time they upgrade the package, if you -haven't changed the file version, their old file will be left in place. -If you have modified your version then the user will get a prompt -asking them which version of the file they want, theirs or yours. They -will then usually have to resolve the discrepancies manually. - - The other option is to be preferred, if you can do it: do not put a -copy of the configuration file in the package at all. Instead, you -check in the postinst whether the file exists, and if it doesn't you -prompt the user for the information you need to create a good one. This -is obviously harder work. - - You also have to remember that you will have to keep up with your -package's changes: if you discover a bug in the program which generates -the configuration file, or if the format of the file changes from one -version to the next, you will have to arrange for the postinst script to -do something sensible--usually this will mean editing the installed -configuration file to remove the problem or change the syntax. You will -have to do this very carefully, since the user may have changed the -file, perhaps to fix the very problem that your script is trying to deal -with--you will have to detect these situations and deal with them -correctly. - - If you do go down this route it's probably a good idea to make the -program that generates the configuration file(s) a separate program in -`/usr/sbin', by convention called package`config', and then run that if -appropriate from the post-installation script. The package`config' -program should not unquestioningly overwrite an existing -configuration--if its mode of operation is geared towards setting up a -package for the first time (rather than any arbitrary reconfiguration -later) you should have it check whether the configuration already -exists, and require a `--force' flag to overwrite it. - - `conffiles' should almost certainly list all the files contained in -your package in the `/etc' directory. There may also be other files -somewhere that the user is expected to edit, which should also be -included. Note, however, that the FSSTND specifies that configuration -files must be in `/etc'. No Debian package should contain -configuration files in `/usr/etc', and all programs should refer to -configuration files in `/etc'. - -For example, the TCP/IP package might use a conffiles which contains - - /etc/init.d/netbase - /etc/gateways - /etc/protocols - /etc/services - /etc/hosts.allow - /etc/hosts.deny - /etc/rpc - -and so on; the files - - /etc/hosts - /etc/inetd.conf - /etc/host.conf - /etc/networks - /etc/resolv.conf - -might be generated by an interactive configuration program, and would -then not be included in the package or listed in the `conffiles'. - - -File: guidelines.info, Node: Installation and Removal Scripts, Next: Dependencies and Conflicts, Prev: conffiles, Up: Control Files - -Installation and Removal Scripts -================================ - - The scripts `preinst', `postinst', `prerm', and `postrm' are -optional (Bash or Perl) scripts. As the names would indicate, if these -scripts exist, they will be executed before installing the package, -after installation, before package removal, and after removal, -respectively. - - They are given arguments which indicate the precise situation and -action being performed--see `maintainer-script-args.txt' for details of -exactly when each of the scripts is invoked and what its arguments are. -Extra arguments and situations may be added later, so you should not -test the number of arguments to your script to determine the situation, -and you should choose the sense of your `if it is this then do this -otherwise do that' tests carefully. - - These scripts can be used to perform any site-specific package -configuration. - - Because the scripts will be exectued by the dpkg front-end, it is -guaranteed that the scripts will be executed interactively. User input -from the scripts should be read from standard input, not the user's -terminal. Similarly, output should be sent to standard output. - - If your maintainer scripts need to prompt for passwords and/or do -full-screen interaction should do these things to and from `/dev/tty', -since `dpkg' will at some point redirect scripts' standard input and -output so that it can log the installation process. Likewise, because -these scripts may be executed with standard output redirected into a -pipe for logging purposes, Perl scripts should set unbuffered output by -setting `$|=1' so that the output is printed immediately rather than -being buffered. - - The scripts must be idempotent, and they must clean up after -themselves properly. Ie, they must do the right thing if run multiple -times, even if previous runs failed halfway through. This is so that if -any errors occur, or if the `dpkg' run is interrupted, the user can -recover by rerunning `dpkg', and/or by upgrading to a new version and -then rerunning the failed operation. - - These scripts should avoid producing output which it is unnecessary -for the user to see and should rely on `dpkg' to stave off boredom on -the part of a user installing many packages. This means, amongst other -things, using the `--quiet' option on `install-info'. - - Packages should try to minimise the amount of prompting they need to -do, and they should ensure that the user will only every be asked each -question once. This means that packages should try to use appropriate -shared configuration files (such as `/etc/papersize' and -`/etc/news/server'), rather than each prompting for their own list of -required pieces of information. - - It also means that an upgrade should not ask the same questions -again, unless the user has used `dpkg --purge' to remove the package's -configuration. The answers to configuration questions should be stored -in an appropriate place in `/etc' so that the user can modify them, and -how this has been done should be documented. - - If a package has a vitally important piece of information to pass to -the user (such as "don't run me as I am, you must edit the following -configuration files first or you risk your system emitting -badly-formatted messages"), it should display this in the `postinst' -script and prompt the user to hit Return to acknowledge the message. -Copyright messages do not count as vitally important (they belong in -`/usr/doc/copyright'; neither do instructions on how to use a program -(these should be in on line documentation, where all the users can see -them). - - They should return a zero exit status for success, or a nonzero one -for failure. Note that if a script is a `#!/bin/sh' script it should -probably start with `set -e', to avoid continuing after errors--see -`bash'(1) for details. Perl scripts should check for errors when -making calls such as `open', `print', `close', `rename' and `system'. - - If these scripts exist they should be left in the `DEBIAN' directory -with execute permission enabled and should contain an appropriate `#!' -line, such as `#!/bin/bash' for a `bash' script or `#!/bin/perl' for a -Perl script (see above). - - -File: guidelines.info, Node: Dependencies and Conflicts, Next: Package Classification Fields, Prev: Installation and Removal Scripts, Up: Control Files - -Conflicts, Depends, Suggests, Recommends and Provides -===================================================== - - The `Depends' field lists packages that are required for this -package to provide a significant amount of functionality. The package -maintenance software will not allow a package to be installed without -also installing packages listed in its `Depends' field, and will run -the `postinst' scripts of packages listed in `Depends' fields before -those of the packages which depend on them, and run the `prerm' scripts -before. - - Packages containing dynamically-linked executable binaries (this -includes almost all C programs) should include a `Depends' field which -mentions the shared C library required for the program to run. For -a.out binaries linked against `libc.so.4' the relevant package name is -`libc' (for the a.out stable 0.93 tree) or `libc4' (for the unstable -development 1.1 tree); for ELF binaries linked against `libc.so.5' the -relevant package name is `libc5'. - - The `Recommends' field lists packages that would be found together -with this one in all but unusual installations. The user-level package -maintenance program `dselect' will warn the user if they select a -package without those listed in its `Recommends' field. Note that -`Recommends' fields do not currently have any implications for the -order in which the maintainer scripts are run. - - The `Suggests' field lists packages that are related to this one and -can perhaps enhance its usefulness, but without which installing this -package is perfectly reasonable. The package maintenance software will -not moan at the user for not selecting `Suggests' related packages, but -may use the information in the `Suggests' field to assist the user -during package selection. - - The syntax of `Depends', `Recommends' and `Suggests' is a list of -groups of alternative packages. Each group is a list of packages -separated by vertical bar (or `pipe') symbols, `|'. The groups are -separated by commas. Each package is a package name optionally -followed by a version number specification in parentheses. A version -number may start with a `>=', in which case that version or any later -will match, or `<=' for that version or any earlier version. A version -number starting with a `>>' or `<<' will respectively match any later -or earlier version. If a version number or a version number starting -with `=' is specified an exact match is required. Commas are to be read -as `AND', and pipes as `OR', with pipes binding more tightly. - - Versions of dpkg before 1.0.9 used `<' and `>' for `<=' and `>=' -(these are still supported for backward compatibility), and did not -support `<<' and `>>'. - - The `Conflicts' field lists packages that conflict with this one, -for example by containing files with the same names (an example would -be Smail vs. Sendmail). The package maintenance software will not -allow conflicting packages to be installed. Two conflicting packages -should each include a `Conflicts' line mentioning the other. - - The syntax of `Conflicts' is a list of package names (with optional -version numbers), separated by commas (and optional whitespace). In -the `Conflicts' field the comma should be read as `OR'. - - The `Provides' field lists the names of any `virtual packages' of -which this packages is to be considered an instantiation. Virtual -packages are used to allow packages to refer to a service they require -(such as the availability of `/usr/sbin/sendmail') without having to -know the names of all the relevant packages. The virtual package names -defined in `Provides' fields may be used in other packages' `Depends', -`Recommends', `Suggests' and `Conflicts' fields. For more information -about how to use virtual packages and which virtual package names to -use read *note Virtual dependencies::. and -`doc/package-developer/virtual-package-names-list.text'. - - The syntax of `Provides' is a list of package names separated by -commas (and optional whitespace). - - -File: guidelines.info, Node: Package Classification Fields, Prev: Dependencies and Conflicts, Up: Control Files - -Priority, Section and Essential -=============================== - - The `Priority' and `Section' fields are used by `dselect' when -displaying the list of packages to the user. There is no need to put -them into a package, since these are usually set by the distribution -maintainers in the `Packages' file. - - However, if a user installs a package which is not part of the -standard distribution, or without downloading and updating from a new -`Packages' file, the information about the priority and section of a -package will be absent, and the `dselect' package listing will have the -package listed under `unclassified'. It is permissible for a package -to include `Section' or `Priority' fields to improve this; however, if -you do this you should make sure you keep the information up to date so -that users are not shown conflicting information. The `Section' field -can also be used by the distribution maintainers as a suggestion about -which section you think is most appropriate for your package. - - The values for the `Section' and `Priority' fields should be -determined by the distribution maintainers; if you don't know what to -put in them just leave them out. You can add them later, if you like, -but remember that you'll then have to reissue your package if the -distribution maintainers change the classification of your package. - - The `Essential' field should only appear in packages in the -installation's base system. If it is set to `yes' then `dpkg' will not -remove the package even if asked to, and will make certain minor -modifications to its installation procedures. The only other legal -value is `no', which is equivalent to the absence of the field. - - - - -File: guidelines.info, Node: Appendix, Prev: Control Files, Up: Top - -Appendix -******** - -* Menu: - -* configuration files - /etc/skel vs /usr/doc/examples:: -* How to write the Description control file field:: -* Configuration of init:: -* Maintainer script arguments and how `dpkg' does things:: -* Mail processing packages:: -* Virtual dependencies:: - diff --git a/doc/guidelines.info-2 b/doc/guidelines.info-2 deleted file mode 100644 index 8018f09f..00000000 --- a/doc/guidelines.info-2 +++ /dev/null @@ -1,744 +0,0 @@ -This is Info file guidelines.info, produced by Makeinfo-1.63 from the -input file ./guidelines.texi. - -START-INFO-DIR-ENTRY -* Guidelines: (guidelines). How to make Debian packages. -END-INFO-DIR-ENTRY - - -File: guidelines.info, Node: configuration files - /etc/skel vs /usr/doc/examples, Next: How to write the Description control file field, Prev: Appendix, Up: Appendix - -configuration files - /etc/skel vs /usr/doc/examples -==================================================== - - There seems to be a certain amount of confusion about `/etc/skel' -and `/usr/doc/examples'. The most important thing to remember is the -following: - - Files in `/etc/skel' will *automatically* be copied into *new* user -accounts by `adduser'. They should not be referenced there by any -program. Files in `/usr/doc/examples' should not be installed -automatically. - - Therefore, if the program in question need a dotfile to exist in -advance in `$HOME' to work *sensibly* that dotfile should be installed -in `/etc/skel' (and listed in conffiles; *note conffiles::.). - - However, programs that require dotfiles in order to operate sensibly -(dotfiles that they do not create themselves automatically, that is) are -a bad thing, and that programs should be configured by the Debian -default installation as close to normal as possible. - - Therefore, if a program in a Debian package needs to be configured in -some way in order to operate sensibly that configuration should be done -in a site-wide global configuration file elsewhere in `/etc' (and that -file should be listed in conffiles). Only if the program doesn't -support a site-wide default configuration should a default per-user file -be placed in `/etc/skel' (and listed in conffiles; *note conffiles::.). - - The idea is as follows: - - The sysadmin should ideally not have to do any configuration other -than that done (semi-)automatically by the postinst script. - - However, if they wish to change their configuration themselves -(because the configuration they want is beyond the scope of the -autoconfiguration, or because the autoconfiguration doesn't exist yet, -or because they just want to do it themselves for any reason) then -`/usr/doc/examples' exists as *documentation* for their benefit. - - The only time these files should be read are by the sysadmin using -their favourite editor or pager, or *perhaps* (in very complex packages) -by the postinst as a template to build on or modify. - - `/etc/skel' is part of the *implementation* of this configuration. -It contains the files that are copied into new user accounts. It -should probably be as empty as we can make it. - - Examples: -`.profile' - `/etc/skel' should not contain a `.profile' file. Anything that - needs to be done there should be done in `/etc/profile'. Anything - that should not go in `/etc/profile' (users can't avoid running - `/etc/profile') probably should not be in the default - configuration. bash has generally good default behaviour. - -`.bash_logout' - Likewise, bash functions perfectly happily without a - `.bash_logout', so none should be provided, since anything in it is - a deviation from the sensible default behaviour. - -`.xsession' - `/etc/skel' should not contain a `.xsession'. `xdm''s system-wide - startup file `/usr/lib/X11/xdm/Xsession' supports a system-wide - default user configuration (which should probably be - `/etc/X11/Xsession' or some such) which may be overridden by - `.xsession' in the user's home directory. Therefore there is no - need for a `.xsession' to be installed by default and none should - be provided. - - Instead, a sensible `/etc/X11/Xsession' should be provided, and if - desired this can be used as a template by users who wish to install - their own configuration, or alternatively a more comprehensive - example with much commented-out interesting stuff could be put in - `/usr/doc/examples'. - - If the sysadmin wishes to change the system-wide default they - should probably do this by editing `/etc/X11/Xsession' rather than - creating the file in `/etc/skel', because the former will affect - all user accounts that haven't explicitly overridden things by - creating their own file while the latter will only affect new - accounts. - - All the configuration necessary for a program to function should be - provided. Therefore sysadmins will not need to go through - `/usr/doc/examples' while editing configuration files in `/etc' - except in extreme cases (like INN) where the configuration was too - difficult to do automatically. - -`site-wide defaults' - Site-wide defaults should not go in `/etc/skel'. In the case of - twm, for example, the system-wide default should be in - `/etc/X11/system.twmrc'. (The default location for this in X11R5, - btw, is in `/usr/lib/X11' somewhere, but we can't put it on `/usr' - because of CDROM distributions, etc - hence the FSSTND's mandate - to put configuration files in `/etc'.) - -`.twmrc' - There should be no `.twmrc' file in `/etc/skel'. You can have one - in `/usr/doc/examples' if you *like*, but why bother if - `system.twmrc' is a good example (and indeed is the one the user is - using before they create their own)? - -`m4' - `/usr/doc/examples' isn't mainly for example *configuration - files*. It's for any kind of example file distributed with a - package. For example, GNU m4 comes with a whole pile of example - m4 macro scripts, which is exactly what `/usr/doc/examples' is for. - - Summary - - Files that should be installed in new user accounts should be in -`/etc/skel', as that will ensure that they *are* installed in new user -accounts! However, we should try to avoid the need for this. - - `/usr/doc/examples' is just what it says: documentation in the form -of examples. If a sysadmin is required to go and read these files for -their system to work they should be told about it. For example, here -is what the Smail postinst script says right at the start: - - I can do certain kinds of automatic configuration of your - mail system, by asking you a number of questions. Later you - may to confirm and/or correct your answers. In any case, - comprehensive information on configuring Smail is in - smail(5) and in /usr/doc/examples/smail and - /usr/doc/smail-admin-guide. - - -File: guidelines.info, Node: How to write the Description control file field, Next: Configuration of init, Prev: configuration files - /etc/skel vs /usr/doc/examples, Up: Appendix - -How to write the Description control file field -=============================================== - - The format of the `Description' field is as follows: - - Description: - - - The extended description has several kinds of line: - - * Those starting with a single space are part of a paragraph. - Successive lines of this form will be word-wrapped when displayed. - The leading space will usually be stripped off. - - * Those starting with two or more spaces. These will be displayed - verbatim. If the display cannot be panned horizontally the - displaying program will linewrap them `hard' (ie, without taking - account of word breaks). If it can they will be allowed to trail - off to the right. None, one or two initial spaces may be deleted, - but the number of spaces deleted from each line will be the same - (so that you can have indenting work correctly, for example). - - * Those containing a single space followed by a single full stop - character. These are rendered as blank lines. This is the *only* - way to get a blank line - see below. - - * Those containing a space, a full stop and some more characters. - These are for future expansion. *Do not* use them. - - IMPORTANT and not so important TIPS: - - * *Always* start extended description lines with at least *one* - whitespace character. Fields in the control file and in the - Packages file are separated by field names starting in the first - column, just as in RFC822. Forgetting the whitespace will cause - `dpkg-deb' (>=0.93.23) to produce a syntax error when trying to - build the package. If you force it to build anyway `dpkg' will - refuse to install the resulting mess. - - * *Do not* include any completely *empty* lines. These separate - different records in the Packages file, and are forbidden in - control files. See the previous paragraph for what happens if you - get this wrong. - - * The single line synopsis should be kept brief - certainly under 80 - characters. `dselect' displays the *first 49* characters if - you're using an 80-column terminal. - - * Do not include the package name in the synopsis line. The display - software knows how to display this already, and you do not need to - state it. Remember that in many situations the user may only see - the synopsis line - make it as informative as you can. - - * The extended description should describe what the package does and - how it relates to the rest of the system (in terms of, for - example, which subsystem it is which part of). - - * Put important information first, both in the synopis and extended - description. Sometimes only the first part of the synopsis or of - the description will be displayed. You can assume that there will - usually be a way to see the whole extended description. - - * You may include information about dependencies and so forth in the - extended description, if you wish. - - * Do not use tab characters. Their effect is not predictable. - - Example control file for Smail: - - Package: smail - Version: 3.1.29.1-13 - Maintainer: Ian Jackson - Recommends: pine | mailx | elm | emacs | mail-user-agent - Suggests: metamail - Depends: cron, libc5 - Conflicts: sendmail - Provides: mail-transport-agent - Description: Electronic mail transport system. - Smail is the recommended mail transport agent (MTA) for Debian. - . - An MTA is the innards of the mail system - it takes messages from - user-friendly mailer programs and arranges for them to be delivered - locally or passed on to other systems as required. - . - In order to make use of it you must have one or more user level - mailreader programs such as elm, pine, mailx or Emacs (which has Rmail - and VM as mailreaders) installed. If you wish to send messages other - than just to other users of your system you must also have appropriate - networking support, in the form of IP or UUCP. - - -File: guidelines.info, Node: Configuration of init, Next: Maintainer script arguments and how `dpkg' does things, Prev: How to write the Description control file field, Up: Appendix - -Configuration of init -===================== - - The `/etc/init.d' directory contains the scripts executed by init(8) -when init state (or "runlevel") is changed. This includes the boot -process, when the multi-user state begins. Several of these scripts -are included with init and are intended to be executed *once*, usually -at boot time. An example is `/etc/init.d/boot', which is executed at -boot time to check and mount file systems, activate swap, load kernel -modules, etc.-everything that needs to be done before the multi-user -state begins. `/etc/init.d' also contains the scripts that are -executed when entering runlevel 0 (halt), runlevel 1 (single-user) and -runlevel 6 (reboot). - - Packages can (and should) place scripts in `/etc/init.d' to start or -stop services at boot time or during a change of runlevel. These -scripts should be named `/etc/init.d/', and they should accept -one of two arguments: "start", which starts the services, or "stop", -which stops the services. These scripts should ensure that they will -behave sensibly if invoked with "start" when the service is already -running, or with "stop2 when it isn't--the best way to achieve this is -often to use `start-stop-daemon'. - - This script should not fail obscurely when the configuration files -remain but the package has been removed, as the default in dpkg is to -leave configuration files on the system after the package has been -removed. Only when it is executed with the `-purge' option will dpkg -remove configuration files. Therefore, you should include a `test' -statement at the top of the script, like this: - - test -f || exit 0 - - These scripts should be referenced, when appropriate, by symbolic -links in the `/etc/rc?.d' directories, as below. - - When changing runlevels, init looks in the directory `/etc/rc.d' -for the scripts it should execute, where is the runlevel that is -being changed to. Please note that the "scripts" in `/etc/rc?.d' are -not actually scripts; they are symbolic links, referencing actual -scripts in `/etc/init.d'. For simplicity, we refer to them as -"scripts". - - First, the scripts prefixed with a "K" are executed, followed by the -scripts prefixed with an "S". The "K" scripts are responsible for -killing certain services and the "S" scripts for starting certain -services upon *entering* the runlevel. For example, if we are changing -from runlevel 2 to runlevel 3, init will first execute all of the "K" -prefixed scripts it finds in `/etc/rc3.d' (to kill services), and then -all of the "S" prefixed scripts it finds in `/etc/rc3.d' (to start -services). The "K" scripts will execute the file it references with an -argument of "stop", and the "S" scripts will execute this file with an -argument of "start". - - After the "K" or "S" prefix, there should be a number specified, and -this number should be between 00 and 99. The number determines the -order in which the scripts are run. For example, the "K20" scripts will -be executed before the "K30" scripts. You can use this number to make -sure that a certain service is started before another. For example, on -some machines, the program `setserial' may need to properly set an IRQ -before the `ppp' program uses a modem to connect to a network. In this -case, the script that runs `setserial' should have a lower number than -the script that starts `ppp' so that it runs first: - - `/etc/rc2.d/S10setserial' - `/etc/rc2.d/S20ppp' - - If it does not matter when or in which order the script is run, use -the number "20". If it does, then you should talk to the maintainer of -the `sysvinit' package or post to `debian-devel', and they will help -you choose a number. - - In Debian GNU/Linux, we try to ship our software in as much of a -"default" state as possible. Therefore, unless there is a good reason -for doing differently, we ask that you start and stop the services in -each of the multi-user state runlevels (2, 3, 4, and 5). If a service -needs to be stopped before a file system can be unmounted (an example is -process accounting or quota services), then be sure to stop them in the -halt runlevel (0), the single-user runlevel (1) and the reboot runlevel -(6). - - The system administrator will have the opportunity to customize -runlevels by simply adding, moving, or removing the symbolic links in -`/etc/rc?.d'. This is why we default to running everything in the -multi-user state-a reasonable default-and the administrator can easily -customize init to be as complex and sophisticated as he or she wants it -to be beyond this. - - We provide a script, `update-rc.d', to make it easier for package -maintainers to arrange for the proper creation and removal of -`/etc/rc?.d' symbolic links from their postinst and postrm scripts. -You should use this script to make changes to `/etc/rc?.d' and *never* -include any `/etc/rc.?.d' symbolic links in the actual archive. - - * In the postinst script, you need only do the following to setup - `/etc/rc?.d'. You should redirect standard output to `/dev/null', - as `update-rc.d' produces insignificant output: - - update-rc.d default >/dev/null - - where is the name of the file as it appears in - `/etc/init.d'. It will use the default number of "20", as - mentioned above. If you need to use a different number, you can - specify it after "default": - - update-rc.d default 30 >/dev/null - - * In the postrm script, you need only do the following *if and only - if* it is called with the `purge' argument: - - if [ purge = "$1" ] - then - update-rc.d remove >/dev/null - fi - -Important Note: ---------------- - - *Do not* include the `/etc/rc?.d/*' symbolic links in the archive! -*This will cause problems!* You should create them with update-rc.d, -as above. - - *Do not* include the `/etc/rc?.d/*' symbolic links in conffiles! -*This will cause problems!* *Do*, however, include the `/etc/init.d' -scripts in conffiles. - -Example: --------- - - The process accounting package wants to make sure that process -accounting is started at boot time and that it is stopped before the -system is halted, enters the single-user state, or is rebooted (so that -the `/var' file system can be properly unmounted). It puts a script -that does this in `/etc/init.d', naming the script appropriately -"acct". This script accepts one of two arguments: either "start", -which starts process accounting, or "stop", which stops it. To ensure -that it does not fail obscurely when the configuration files remain but -the package has been removed, we include a `test' statement at the top -of the script: - - #! /bin/sh - # - # Start process accounting. - . /etc/init.d/functions - test -f /usr/sbin/accton || exit 0 - case "$1" in - start) - echo "Starting process accounting" - /usr/sbin/accton /var/account/pacct - ;; - stop) - echo "Stopping process accounting" - /usr/sbin/accton - ;; - *) - echo "Usage: /etc/init.d/acct {start|stop}" - exit 1 - esac - exit 0 - - You may find a skeletal script from which to base your `/etc/init.d' -scripts in `/etc/init.d/skeleton'. - - We want to stop then (re)start process accounting when entering a -multi-user state-runlevels 2, 3, 4, and 5-and we want to stop it when -leaving such a state-runlevels 0 (halt), 1 (single) and 6 (reboot). -These are good defaults, and we accomplish this by including the -following in the postinst: - - update-rc.d acct default >/dev/null - - When the user removes the acct packages with the `-purge' option, we -want to make sure the `/etc/rc?.d' symbolic links are properly removed, -so we include the following in the postrm: - - update-rc.d acct remove >/dev/null - - Otherwise, the `/etc/rc?.d' symbolic links will remain on the system -along with `/etc/init.d/acct' script. - - -File: guidelines.info, Node: Maintainer script arguments and how `dpkg' does things, Next: Mail processing packages, Prev: Configuration of init, Up: Appendix - -Maintainer script arguments and how `dpkg' does things -====================================================== - - This appendix describes exactly how maintainer scripts are called, -with what arguments, in what order, and what `dpkg' does in between. - - In all cases version numbers are -, if the package -has both, or just . `upgrade' is used even when the new -version number looks lower than the old. - -Summary -------- - - install - install - upgrade - abort-upgrade - - configure - abort-upgrade - abort-remove in-favour - abort-deconfigure \ - in-favour - removing - - remove - upgrade - failed-upgrade - remove in-favour - deconfigure \ - in-favour \ - removing - - remove - purge - upgrade - failed-upgrade - abort-install - abort-install - abort-upgrade - disappear - -Details of unpack phase of installation or upgrade --------------------------------------------------- - - The procedure on installation/upgrade/overwrite/disappear (ie, when -running `dpkg --unpack', or the unpack stage of `dpkg --install') is as -follows. In each case if an error occurs the actions in are general -run backwards - this means that the maintainer scripts are run with -different arguments in reverse order. These are the `error unwind' -calls listed below. - - 1. - a. If a version the package is already installed, call - upgrade - - b. If this gives an error (ie, a non-zero exit status), dpkg will - attempt instead: - failed-upgrade - error unwind, for both the above cases: - abort-upgrade - - 2. If a `conflicting' package is being removed at the same time: - a. If any packages depended on that conflicting package and - `--auto-deconfigure' is specified, call, for each such - package: - deconfigure \ - in-favour \ - removing - error unwind: - abort-deconfigure \ - in-favour - removing - The deconfigured packages are marked as requiring - configuration, so that if -install is used they will be - configured again if possible. - - b. To prepare for removal of the conflicting package, call: - remove in-favour - error unwind: - abort-remove in-favour - - 3. - a. If the package is being upgraded, call - upgrade - - b. otherwise, if the package had some configuration files from a - previous version installed (ie, it is in the conffiles-only - state): - install - - c. otherwise (ie, the package was completely purged): - install - error unwind versions, respectively: - abort-upgrade - abort-install - abort-install - - 4. The new package's files are unpacked, overwriting any that may be - on the system already, for example any from the old package or - from another package (backups of the old files are left around, - and if anything goes wrong dpkg will attempt to put them back as - part of the error unwind). - - 5. - a. If the package is being upgraded, call - upgrade - - b. If this fails, dpkg will attempt: - failed-upgrade - error unwind, for both cases: - abort-upgrade - This is the point of no return - if dpkg gets this far, it - won't back off past this point if an error occurs. This will - leave the package in a fairly bad state, which will require a - successful reinstallation to clear up, but it's when dpkg starts - doing things that are irreversible. - - 6. Any files which were in the old version of the package but not in - the new are removed. - - 7. The new file list replaces the old. - - 8. The new maintainer scripts replace the old. - - 9. Any packages all of whose files have been overwritten during the - installation, and which aren't required for dependencies, are - considered to have been removed. For each such package, - a. dpkg calls: - disappear - - b. The package's maintainer scripts are removed. - - c. It is noted in the status database as being in a sane state, - namely not installed (any conffiles it may have are ignored). - Note that disappearing packages do not have their prerm - called, because dpkg doesn't know in advance that the package - is going to vanish. - - 10. Any files in the package we're unpacking that are also listed in - the file lists of other packages are removed from those lists. - (This will lobotomise the file list of the `conflicting' package - if there is one.) - - 11. The backup files made at 4. are deleted. - - 12. The new package's status is now sane, and recorded as `unpacked'. - Here is another point of no return - if the conflicting package's - removal fails we do not unwind the rest of the installation; the - conflicting package is left in a half-removed limbo. - - 13. If there was a conflicting package we go and do the removal - actions, starting from point 2. of the removal, below. - -Details of configuration ------------------------- - - When we configure a package (this happens with `dpkg --install', or -with `--configure'), we first update the conffiles and then call: - configure - - No attempt is made to unwind after errors during configuration. - -Details of removal and/or configration purging ----------------------------------------------- - - 1. remove - - 2. The package's files are removed (except conffiles). - - 3. remove - - 4. All the maintainer scripts except the postrm are removed. - - If we aren't purging the package we stop here. Note that packages - which have no postrm and no conffiles are automatically purged - when removed, as there is no difference except for the dpkg status. - - 5. The conffiles and any backup files (`~'-files, `#*#' files, - `%'-files, .dpkg-{old,new,tmp}, etc.) are removed. - - 6. purge - - 7. The package's file list is removed. - No attempt is made to unwind after errors during removal. - - -File: guidelines.info, Node: Mail processing packages, Next: Virtual dependencies, Prev: Maintainer script arguments and how `dpkg' does things, Up: Appendix - -Mail processing packages -======================== - - Debian packages which process electronic mail (whether -mail-user-agents (MUA) or alternative mail-transport-agents (MTA)) -*must* make sure that they are compatible with the configuration -decisions below. Failure to do this may result in lost mail, broken -`From:' lines, and other serious brain damage! - - * The mail spool is `/var/spool/mail' and the interface to send a - mail message is `/usr/sbin/sendmail' (as per the FSSTND). The mail - spool is part of the base and not part of the MTA package. - - * Mailboxes are locked using the `.lock' lockfile convention, rather - than fcntl, flock or lockf. - - * Mailboxes are generally 660 `.mail' unless the user has - chosen otherwise. A MUA may remove a mailbox (unless it has - nonstandard permissions) in which case the MTA or another MUA must - recreate it if needed. Mailboxes must be writeable by group mail. - - * The mail spool is 2775 mail.mail, and MUA's need to be setgid mail - to do the locking mentioned above (and obviously need to avoid - accessing other users' mailboxes using this privilege). - - * `/etc/aliases' is the source file for the system mail aliases (e.g. - postmaster, usenet, etc.) - it is the one which the sysadmin and - postinst scripts may edit. - - * The convention of writing `forward to
' in the mailbox - itself is not supported. Use a `.forward' file instead. - - * The location for the `rmail' program used by UUCP for incoming mail - is `/usr/sbin/rmail', as per the FSSTND. Likewise, `rsmtp', for - receiving batch-SMTP-over-UUCP, is in `/usr/sbin/rsmtp' if it is - supported. - - * Smail is not using HoneyDanBer UUCP, whose uux apparently accepts - -a and -g options. - - * If you need to know what name to use (for example) on outgoing - news and mail messages which are generated locally, you should use - the file `/etc/mailname'. It will contain the portion after the - username and `@' sign for email addresses of users on the machine - (followed by a newline). - - A package should check for the existence of this file. If it exists -it should use it without comment (1). If it does not exist it should -prompt the user for the value and store it in `/etc/mailname' as well -as using it in the package's configuration. The prompt should make it -clear that the name will not just be used by that package. E.g., in -the same situation the INN package says: - - Please enter the `mail name' of your system. This is the hostname - portion of the address to be shown on outgoing news and mail messages. - The default is `$syshostname', your system's host name. - Mail name [`$syshostname']: - ($syshostname is the output of `hostname -fqdn'). - - ---------- Footnotes ---------- - - (1) An MTA's prompting configuration script may wish to prompt the -user even if it finds this file exists. - - -File: guidelines.info, Node: Virtual dependencies, Prev: Mail processing packages, Up: Appendix - -Virtual dependencies -==================== - - Virtual packages are in the same namespace as real packages, and may -have the same name. The meaning of a virtual package in a -dependency/conflicts list is exactly that of listing all the real -packages which state that they are an instantiation of that virtual -package. - - This is done with a new Provides field in the control file, with a -syntax much like the Conflicts field. - - The idea is that we can have something like: - Package: elm - Depends: mta - - Package: smail - Provides: mta - Conflicts: mta - - Package: sendmail - Provides: mta - Conflicts: mta - The result is equivalent to elm having said - Package: elm - Depends: smail | sendmail - - (There'll be a special case to say that a package may conflict with a -virtual package which it provides - clearly ...) - - If there are both a real and a virtual package of the same name then -the dependency may be satisfied (or the conflict caused) by either the -real package or any of the virtual packages which provide it. This is -so that, for example, supposing we have - Package: lout - Optional: ghostview - (this is a fictional example - the Lout package should not mention -ghostview), and someone else comes up with a nice PostScript previewer, -then they can just say - Package: marvelpostview - Provides: ghostview - and all will work in the interim (until, say, the Lout maintainer -changes things). - - If a dependency or a conflict has a version number attached then only -real packages will be considered to see whether the relationship is -satisfied (or prohibited, for a conflict) - it is assumed that a real -package which provides virtual package is not of the `right' version. -If there is demand it can be arranged that a package which provides a -virtual package may mention a version number, though this is unlikely to -be helpful: - Provides: mta (2.0) - - If you want to specify which of a set of real packages should be the -default to satisfy a particular dependency on a virtual package, you can -simply list the real package as alternative before the virtual one: - Package: xbaseR6 - Recommended: xsvga | x-server - Provides: x-base, xr6shlib - - Package: xsvga - Recommended: x-base - Provides: x-server - - Package: x8514 - Recommended: x-base - Provides: x-server - - Virtual package names should generally not be used in the names of -`/etc/init.d' scripts, configuration files, logfiles, and so on, so -that several programs providing the same virtual package name can be -installed. - - diff --git a/doc/guidelines.texi b/doc/guidelines.texi index 21c5d9f5..b979679e 100644 --- a/doc/guidelines.texi +++ b/doc/guidelines.texi @@ -6,7 +6,7 @@ @setchapternewpage off @iftex -@center @titlefont{Debian GNU/Linux Packaging Guidelines} +@center @titlefont{Debian Linux Packaging Guidelines} @tex \vskip2pt \hrule height 2pt width \hsize \vskip2pt @end tex @@ -25,11 +25,11 @@ END-INFO-DIR-ENTRY @node Top, Additional Information, (dir), (dir) @ifinfo -@top Debian GNU/Linux Packaging Guidelines +@top Debian Linux Packaging Guidelines @end ifinfo This file documents the steps that must be taken in the preparation -of a Debian GNU/Linux package. All submissions to be included in the +of a Debian Linux package. All submissions to be included in the distribution proper and all packages to be considered for @file{contrib} or @file{non-free} availability @emph{must} conform to the guidelines and standards described in this document or they cannot be included or @@ -41,11 +41,11 @@ planning on going further than just contributing a package (i.e., if you plan to maintain it for an extended period of time or if you are generally interested in becoming more involved in the Project), you should join the @code{debian-devel} mailing list. For more details, -read @file{info/mailing-lists.txt}, available at any Debian GNU/Linux +read @file{info/mailing-lists.txt}, available at any Debian Linux archive. (This file was last updated on @value{DATE}. Please check the most -recent @file{dpkg} package at any Debian GNU/Linux archive for a +recent @file{dpkg} package at any Debian Linux archive for a potentially more up to date copy.) @menu @@ -66,10 +66,10 @@ potentially more up to date copy.) These Guidelines are intended to be fairly general. More specific information is available about certain aspects of building packages, -such as how to use the features of Init under Debian GNU/Linux and how +such as how to use the features of Init under Debian Linux and how to interact with some more technical details of dpkg's operation. This information can be found in the directory @file{doc/package-developer} -at any Debian GNU/Linux archive. At the time of this writing, the +at any Debian Linux archive. At the time of this writing, the following documents are available: @table @file @@ -174,11 +174,11 @@ personal purposes. Software that will typically be included in software that does not allow modification or redistribution of modifications, commercial ``demos'', and ``shareware''. - When in doubt, send mail to @file{iwj10@@cus.cam.ac.uk} and -@file{imurdock@@debian.org}. Be prepared to provide us with the -copyright statement. Software covered by the GPL, public domain -software and BSD-like copyrights are safe; be wary of the phrases -``commercial use prohibited'' and ``distribution restricted''. + When in doubt, send mail to @file{debian-devel@@lists.debian.org}. +Be prepared to provide us with the copyright statement. Software +covered by the GPL, public domain software and BSD-like copyrights are +safe; be wary of the phrases ``commercial use prohibited'' and +``distribution restricted''. Every package submission @emph{must} be accompanied by verbatim copy of its copyright (with the exceptions of public domain packages and @@ -196,7 +196,7 @@ See below for details. source packages. In either case, when files have been installed, they must conform to the requirements described in this section. - The primary rule in Debian GNU/Linux is to follow the Linux @dfn{File + The primary rule in Debian Linux is to follow the Linux @dfn{File System Standard} (@dfn{FSSTND}). The location of installed files @emph{must} comply @emph{fully} with the FSSTND. The latest version of this document can be found alongside the Guidelines or at @@ -204,7 +204,7 @@ this document can be found alongside the Guidelines or at Specific questions about following the standard should be addressed to Daniel Quinlan, the FSSTND coordinator, at @code{quinlan@@yggdrasil.com}. - In addition to the FSSTND, all Debian GNU/Linux packages must follow + In addition to the FSSTND, all Debian Linux packages must follow the guidelines below. @itemize @bullet @@ -587,7 +587,7 @@ This will create a file called @file{debian-tmp.deb}, from the After the @file{binary} target has done all this, the @file{<@i{package}>-<@i{version}>.deb} file in the parent directory is the binary distribution. This file may be distributed and installed on -any Debian GNU/Linux system with @file{dpkg} in the same manner and +any Debian Linux system with @file{dpkg} in the same manner and using the same methods as all packages are installed to the system. @item @@ -1359,7 +1359,7 @@ scripts should be named @file{/etc/init.d/}, and they should accept one of two arguments: "start", which starts the services, or "stop", which stops the services. These scripts should ensure that they will behave sensibly if invoked with "start" when the service is already -running, or with "stop2 when it isn't---the best way to achieve this is +running, or with "stop" when it isn't---the best way to achieve this is often to use @file{start-stop-daemon}. This script should not fail obscurely when the configuration files @@ -1414,14 +1414,11 @@ number "20". If it does, then you should talk to the maintainer of the @code{sysvinit} package or post to @code{debian-devel}, and they will help you choose a number. -In Debian GNU/Linux, we try to ship our software in as much of a +In Debian Linux, we try to ship our software in as much of a "default" state as possible. Therefore, unless there is a good reason -for doing differently, we ask that you start and stop the services in -each of the multi-user state runlevels (2, 3, 4, and 5). If a service -needs to be stopped before a file system can be unmounted (an example is -process accounting or quota services), then be sure to stop them in the -halt runlevel (0), the single-user runlevel (1) and the reboot runlevel -(6). +for doing differently, we ask that you start the services in each of the +multi-user state runlevels (2, 3, 4, and 5) and stop them in the halt +runlevel (0), the single-user runlevel (1) and the reboot runlevel (6). The system administrator will have the opportunity to customize runlevels by simply adding, moving, or removing the symbolic links in diff --git a/doc/guidelines.texi.beforeeric b/doc/guidelines.texi.beforeeric deleted file mode 100644 index fb2f2953..00000000 --- a/doc/guidelines.texi.beforeeric +++ /dev/null @@ -1,1056 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@setfilename guidelines.info - -@set DATE 26th January 1996 - -@setchapternewpage off - -@iftex -@center @titlefont{Debian GNU/Linux Packaging Guidelines} -@tex -\vskip2pt \hrule height 2pt width \hsize \vskip2pt -@end tex -@sp 0.5 -@center @value{DATE} -@end iftex - -@ifinfo -@format -START-INFO-DIR-ENTRY -* debian-guidelines: (debian-guidelines). How to make Debian packages. -END-INFO-DIR-ENTRY -@end format -@end ifinfo - -@node Top, Additional Information, (dir), (dir) - -@ifinfo -@top Debian GNU/Linux Packaging Guidelines -@end ifinfo - - This file documents the steps that must be taken in the preparation -of a Debian GNU/Linux package. All submissions to be included in the -distribution proper and all packages to be considered for @file{contrib} -or @file{non-free} availability @emph{must} conform to the guidelines -and standards described in this document or they cannot be included or -made available at the archive with the distribution. - - Please read the Guidelines carefully. If you have comments or -questions, please contact @code{debian-devel@@pixar.com}. If you are -planning on going further than just contributing a package (i.e., if -you plan to maintain it for an extended period of time or if you are -generally interested in becoming more involved in the Project), you -should join the @code{debian-devel} mailing list. For more details, -read @file{info/mailing-lists.txt}, available at any Debian GNU/Linux -archive. - - (This file was last updated on @value{DATE}. Please check the most -recent @file{dpkg} package at any Debian GNU/Linux archive for a -potentially more up to date copy.) - -@menu -* Additional Information:: -* Package Copyright:: A few words about the importance of - understanding the package copyright. -* Package Content:: Requirements for the package content. -* Source Package:: Creating the source package. -* Binary Package:: Creating the binary package. -* Control Files:: The binary package control files. -@end menu - - - -@node Additional Information, Package Copyright, Top, Top -@unnumbered Additional Information - - These Guidelines are intended to be fairly general. More specific -information is available about certain aspects of building packages, -such as how to use the features of Init under Debian GNU/Linux. This -information can be found in the directory @file{project/standards} -at any Debian GNU/Linux archive. At the time of this writing, the -following documents are available: - -@table @file -@item README.etc-skel -A description of @file{/etc/skel} and @file{/usr/doc/examples}. -@item descriptions.txt -How to write an extended (and more useful) @file{DESCRIPTION} field. -@item README.init -How to use the features of Init under Debian GNU/Linux in packages. -@item mailers.txt -How to properly configure packages to use the Debian GNU/Linux mail -system. -@item maintainer-script-args.txt -All the ways that the package maintainer scripts inside a package can -be called by dpkg. -@item dpkg-upgrades+errors.txt -What order things happen in during a package upgrade. -@item virtual-dependencies.txt -How to use ``virtual dependencies'' in packages. -@item virtual-package-names-list.text -The list of virtual package names currently in use, together with the -procedure for getting new virtual package names allocated. -@item dependency-ordering.txt -How to properly order package names in the @file{DEPENDS} field. -@end table - - There are a number of documents that describe more technical -details of dpkg's operation, that will probably only be of minority -interest. Please read them if you're doing anything complicated. - -@table @file -@item auto-deconfiguration.txt -How dpkg can sometimes automatically deconfigure packages in order to -do bulk installations smoothly. -@item dpkg-essential-flag.txt -How to tell dpkg a package is essential and should not be removed. -(This is for the use of base system packages only.) -@item dpkg-disappear-replace.txt -What happens when a package appears to have been completely replaced. -@end table - - In the future, we hope also to make available: - -@table @file -@item copyright.txt -How to choose a good copyright notice to attach to new programs. -@item version-ordering.txt -The algorithm with which packages' version numbers are compared. -@end table - - Also, you should download the sample files and the sample package -(GNU Hello) available in @file{standards/samples}. You may use any -of this material as a starting point for new packages. The following -sample files, incidentally, are available: - -@itemize @bullet -@item debian.README -@item debian.control -@item debian.postinst -@item debian.postrm -@item debian.rules -@end itemize - - - -@node Package Copyright, Package Content, Additional Information, Top -@unnumbered Package Copyright - - Please study the copyright of your submission @emph{carefully} -and @emph{understand it} before proceeding! If you have doubts or -questions, please ask! - - In order to understand how we classify and distribute certain -packages, it is important to understand the distinction between being -freely available and being freely redistributable. - - Being @dfn{freely available}, quite simply, means that the software -can be made available freely, at least for non-commercial purposes and -in its original, unmodified form. This includes packages made available -freely that have restrictions on non-commercial use, redistribution of -modifications, etc. Being freely available, therefore, has nothing to -do with being able to modify and redistribute the software. It only -means that you can get a copy of the software without having to pay -(and it does not necessarily mean that you can @emph{use} the software -without having to pay---shareware is an example of freely available -software). - - @dfn{freely redistributable}, while generally being freely available, -goes beyond just being freely available. Freely redistributable means -that that the software, in addition to being able to be made available -freely, must be able to be freely modified and redistributed without -restriction. - - All submissions to be included in the distribution proper @emph{must} -be freely redistributable. - - In addition to the distribution, the Project maintains two separate -archives of software packages with the distribution: the @file{contrib} -archive and the @file{non-free} archive. - - @file{contrib} is an archive of user-contributed packages that are -not maintained by the Project, packages that were once maintained by the -Project but that are no longer actively maintained, and packages that -are maintained by the Project but that are not yet considered ready for -inclusion in the distribution proper (i.e., ALPHA and BETA packages). -As above, all submissions for inclusion in the @file{contrib} archive -@emph{must} be freely redistributable. - - @file{non-free} is an archive of packages with either restrictive or -unclear terms of copying or modification. If a package has @emph{any} -restrictions on modification or redistribution, it can not be included -in the distribution or @file{contrib} archive. It can only be included -in the @file{non-free} archive, and then only if it is freely available. - - In summary, in order to be included in the distribution proper or the -@file{contrib} archive, a package must be @emph{freely redistributable}. -Anyone must be able to make copies of it, modify it, redistribute it with -their modifications in place, include it on a CD-ROM, or generally sell -it. To be included in the @file{non-free} archive, a package may have -restrictions, as long as the package remains @emph{freely available}. We -must be available to make it available freely at the archive, and anyone -must be able to make copies of it and use it for at least non-commercial, -personal purposes. Software that will typically be included in -@file{non-free} are software that does not allow commercial distribution, -software that does not allow modification or redistribution of -modifications, commercial ``demos'', and ``shareware''. - - When in doubt, send mail to @file{iwj10@@cus.cam.ac.uk} and -@file{imurdock@@debian.org}. Be prepared to provide us with the -copyright statement. Software covered by the GPL, public domain -software and BSD-like copyrights are safe; be wary of the phrases -``commercial use prohibited'' and ``distribution restricted''. - - Every package submission @emph{must} be accompanied by verbatim copy -of its copyright (with the exceptions of public domain packages and -those covered by the UCB BSD licence or the GNU GPL or LGPL; in these -cases simply indicate which is appropriate). This information must be -included in a file installed to the directory @file{/usr/doc/copyright}. -See below for details. - - - -@node Package Content, Source Package, Package Copyright, Top -@unnumbered Package Content - - The following requirements apply equally to both the binary and -source packages. In either case, when files have been installed, -they must conform to the requirements described in this section. - - The primary rule in Debian GNU/Linux is to follow the Linux @dfn{File -System Standard} (@dfn{FSSTND}). The location of installed files -@emph{must} comply @emph{fully} with the FSSTND. The latest version of -this document can be found alongside the Guidelines or at -@file{tsx-11.mit.edu} in @file{/pub/linux/docs/linux-standards/fsstnd}. -Specific questions about following the standard should be addressed to -Daniel Quinlan, the FSSTND coordinator, at @code{quinlan@@yggdrasil.com}. - - In addition to the FSSTND, all Debian GNU/Linux packages must follow -the guidelines below. - -@itemize @bullet -@item -Directories should be mode 755 or (for group-writability) mode 2775, -with the exception of special ``system'' directories that need to be -another mode. The ownership of the directory should be consistent with -its mode---if a directory is mode 2775, it should be owned by the group -that needs write access to it, of course. Use common sense in assigning -permissions and ownerships to directories, and make sure that what is -done is secure if it is ``non-standard''. - -@item -Normal binaries should be mode 755 and owned by @code{root.root}. If -there is a good reason to use a different mode or ownership, you may do -so, but you must try to be as consistent as possible with the rest of -the system. If you need to use a different mode or ownership, please -discuss it with @code{imurdock@@debian.org}. - -@item -Setuid binaries should normally be mode 4755 (not 4711!) and, of course, -owned by the appropriate user. - -@item -Setgid binaries should normally be mode 2755 (not 2711!) and, of course, -owned by the appropriate group. - -@item -Library files should generally be mode 644 and owned by -@code{root.root}. If the package requires different permissions -or ownerships to function correctly, they should be used instead. - -@item -Manual pages should be mode 644 and owned by @code{root.root}. The -@file{nroff} source must be installed. You should @emph{not} install -a preformatted ``cat page'', and you should only use sections 1 to -9---see the FSSTND for more details. - -@item -Info documents should be mode 644, owned by @code{root.root}, and -compressed with @file{gzip -9} when installed. The package must call -@file{install-info} to update the Info @file{dir} file. This should -be done in the post-installation script (@file{postinst}), like this: - -@smallexample - install-info --quiet /usr/info/foobar.info -@end smallexample - -The entries should be removed by the pre-removal script (@file{prerm}), -like this: - -@example - install-info --quiet --remove /usr/info/foobar.info -@end example - -It is also a good idea to specify a section for the Info @file{dir} -entry. This is done with the @file{--section} switch. To determine -which section to use, you should use look at @file{/usr/info/dir} on -your system and choose the most relevant (or create a new section if -none of the current sections are relevant). - -If @file{install-info} cannot find a description entry in the Info file -you will have to supply one. See @file{install-info}(8) for details. - -@item -If a package contains any shared libraries you will have to invoke -@file{ldconfig} in both the @file{postinst} and @file{prerm} scripts -to correctly update the library links. See @file{ldconfig}(8) for -details. - -@item -Any additional documentation that comes with the package can be -installed at the discretion of the package maintainer. Text -documentation should be mode 644, owned by @code{root.root}, installed -to @file{/usr/doc}, and compressed with @file{gzip -9} unless it is small. - -If a subdirectory of @file{/usr/doc} is warranted, please do create one. -Please do not install DVI, PostScript, or large textual documentation to -@file{/usr/doc}. However, please do upload such documentation as a -separate package so that it can be made available with the distribution. -If a user has the need for the documentation, they can easily get it -from the archive, CD-ROM, etc., but it should not take up disk space -on the machines of the user who do not need or want it installed. - -@item -Create a file named @file{/usr/doc/copyright/<@i{package}>} which gives -details of the authorship and copyright of the package. If the package -is distributed under the GNU General Public Licence, the GNU Library -General Public Licence or the Regents of the University of California at -Berkeley (BSD) licence, please say so instead of including a copy of the -licence. The files @file{BSD}, @file{GPL}, and @file{LGPL} will be -available in the @file{/usr/doc/copyright} directory for you to refer -to. @file{/usr/doc/copyright/<@i{package}>} should not be compressed. - -@emph{All} authorship and copyright information from the original source -package must be included in the @file{/usr/doc/copyright/<@i{package}>} -file. - -@item -Any example files (for example, sample configuration files) should -be placed in the directory @file{/usr/doc/examples}. If the file is -normally a hidden file, such as @file{.emacs}, then please call it -@file{dot.emacs}, to avoid confusion. Again, you may create a -subdirectory if it is needed. - -@item -All symbolic links should be relative, not absolute. Absolute links, -in general, cause problems when a file system is not mounted where it -``normally'' resides (for example, when mounted via NFS). In certain -cases, however, relative links may also cause similar problems. I -have generally made links into @file{/etc} and @file{/var} absolute -and all other links relative. There may be other cases in which -absolute links are necessary. - -Therefore, in the Makefile, do not do (even though it is easier): -@smallexample - install: all - [...] - ln -fs /usr/bin/gcc /usr/bin/cc - [...] -@end smallexample -Instead, do: -@smallexample - ln -fs gcc /usr/bin/cc -@end smallexample - or -@smallexample - ( cd /usr/bin ; ln -fs gcc cc ) -@end smallexample - -Please do not create hard links in the manual page directories. In -these cases, you should use relative symbolic links or files that -@file{.so} (roff for `source') others instead. - -@item -All command scripts should have a @code{#!} line naming the shell to be -used to interpret them. - -@item -In the case of Perl scripts this should be @code{#!/usr/bin/perl} or -sometimes @code{#!/bin/perl}, as follows: if the script is a critical -one that may be called when the @file{/usr} partition is unmounted or -broken it should use @file{/bin/perl}. Otherwise (especially if the -script is not specifically targetted at Debian) it should use Perl's -standard location, @file{/usr/bin/perl}. - -@item -Generally the following compilation parameters should be used: - -@display - CC = gcc - CFLAGS = -O2 -g -Wall # sane warning options vary between programs - LDFLAGS = # none (or -N, if appropriate; see below) - install -s (or strip) -@end display - -Note that all installed binaries should be stripped, either by using the -@code{-s} flag to @file{install}, or by calling @file{strip} on the -binaries after they have been copied into the @file{debian-tmp} but -before the tree is made into a package. - -Make sure that you do not link with @code{-g}, as this makes a.out -compilers produce huge statically linked binaries. The @code{-g} flag -is useful on compilation so that you have available a full set of -debugging symbols in your built source tree, in case anyone should file -a bug report involving (for example) a core dump. - -@code{-N} should only be used on binaries that are very small (less than -8K with the @code{-N} option, roughly) and are not likely to have -multiple instances in memory. Do not use @code{-N} on daemons, no -matter how small they are. - -It is up to the package maintainer to decide what compilation options -are best for the package. Certain binaries (such as -computationally-intensive programs) may function better with certain -flags (@code{-O3}, for example); feel free to use them. Please use good -judgment here. Don't add flags for the sake of adding flags; only add -flags if there is good reason to do so. - -@item -Please check with the base system maintainer (Ian Murdock) before using -users or groups other than @code{root} and others specified in this -document. -@end itemize - - - -@node Source Package, Binary Package, Package Content, Top -@unnumbered Source Package - - The source package should contain a file called @file{debian.rules} -which contains at least the following targets, to be invoked in the top -level directory: - -@smallexample -build -binary -clean -@end smallexample - -@file{debian.rules} should start with - -@example - #!/usr/bin/make -f -@end example - -@noindent and be executable. It is a good idea to arrange for it not -to fail obscurely when invoked in the wrong directory, for example by -testing for the existence of a file in the source directory. - -@itemize @bullet -@item -The @file{build} target should perform all non-interactive configuration -and compilation of the package. If a package has an interactive -pre-build configuration routine, the source package should be built -@emph{after} this has taken place. - - For some packages, notably ones where the same source tree is -compiled in different ways to produce two binary packages, the -@file{build} target does not make much sense. For these packages it is -good enough to provide two (or more) targets (@file{build-a} and -@file{build-b} or whatever) for each of the ways of building the -package, and a @file{build} target that does nothing. The @file{binary} -target will have to build the package in each of the possible ways and -make the binary package out of each. - -@item -The @file{binary} target of @file{debian.rules} should be all that is -necessary for the user to build the binary package. The binary package -should be created using @file{dpkg} and placed in the parent of the top -level directory. The next section describes how to construct binary -packages from the @file{binary} target. - -@item -The @file{clean} target should undo the effects of the @file{build} -target and the @file{binary} target, except that it should leave alone -any @file{../<@i{package}>-<@i{version}>.deb} file created by a run of -@file{binary}. - -@item -Additional targets may exist in @file{debian.rules}. We recommend using -@file{source} and @file{diff} targets to build the Debianised source -package and the Debianisation context diff, respectively. These files -should be placed in @file{../foo-<@i{version}>.tar.gz} and -@file{../foo-<@i{version}>.diff.gz}. The @file{install} target, for -installing into a running system direct from the Debianised source -tree, is no longer required. The sample @file{debian.rules} provides -@file{source} and @file{diff} targets that should work with little or -no alteration, providing that the package-specific variables at the top -of the script have been properly defined. - -@item -If you need to edit a @file{Makefile} where @file{configure} scripts -are used, you should edit the @file{.in} files rather than editing -the @file{Makefile} directly. This allows the user to reconfigure -the package if necessary. You should @emph{not} configure the package -and edit the generated @file{Makefile}! This makes it impossible for -someone else to later reconfigure the package. - -@item -Please document your changes to the source package so that future -package maintainers know what has been changed. To do this, include -a description of your changes in the @file{debian.README} (which, as -described above, should already contain authorship and copyright -information!) and include relevant information such as your name, -electronic mail address, date, etc. - -@item -If changes to the source code are made, please use a @file{define}. If -they are changes required to compile or function under Linux in general, -use @file{LINUX}. If it is a cosmetic or functional change, use -@file{DEBIAN}. - -@item -Create the source package using @file{tar}, and use @file{gzip -9} to -compress it. Source packages should be named in the form -<@i{package}>-<@i{version}>.tar.gz---for example, -@file{fileutils-3.9-3.tar.gz}. - -NB, here @code{<@i{version}>} is the full Debian version number, in the -form @code{<@i{original_version}>-<@i{debian_revision}>} (see below), -but the tarfile should unpack into a directory named -@code{<@i{package}>-<@i{original_version}>} (again, see the section -below on version numbering). - -@item -Create the context diff against the original package using @file{diff --cNr}, and use @file{gzip -9} to compress it. Context diffs should be -named in the form <@i{package}>-<@i{version}>.diff.gz---for example, -@file{fileutils-3.9-3.diff.gz}. -@end itemize - - Please note that the package and patch filenames do @emph{not} need -to fit in MS-DOS 8+3. They will be made available under an alternative -8+3 name in the archive by the archive maintainer, using a symlink. - - - -@node Binary Package, Control Files, Source Package, Top -@unnumbered Binary Package - - The @file{binary} target of the source package @file{debian.rules} -file should do the following (see the sample @file{debian.rules} -for an implementation that you are free to modify and use in your own -packages, of course): - -@itemize @bullet -@item -Create an empty directory in the top-level directory of the source -package (deleting it first, if necessary), and install the files -belonging to this package in that directory. For example, the directory -could be called @file{debian-tmp} and would probably contain directories -@file{debian-tmp/usr/bin}, @file{debian-tmp/usr/lib}, etc. -(@file{debian-tmp} is the name traditionally used, and it is used in -the sample @file{debian.rules} file, so we will use that name in the -Guidelines.) - -@item -Make sure that all the files under @file{debian-tmp} have the correct -ownerships and permissions (@pxref{Package Content}, for more information -about file locations, ownerships, and permissions.) - -@item -Create a subdirectory of @file{debian-tmp} called @file{DEBIAN}. This -directory contains the package control information, including at the -very least the master information file named @file{control}. The next -section describes the semantics and syntax of the files required and -allowed here. - -@item -Run @file{dpkg} to create the binary package, using something like - -@smallexample - dpkg --build debian-tmp -@end smallexample - -This will create a file called @file{debian-tmp.deb}, from the -@file{debian-tmp} directory. You should rename this file to -@file{../<@i{package}>-<@i{version}>.deb} after it is built. - -After the @file{binary} target has done all this, the -@file{<@i{package}>-<@i{version}>.deb} file in the parent directory is -the binary distribution. This file may be distributed and installed on -any Debian GNU/Linux system with @file{dpkg} in the same manner and -using the same methods as all packages are installed to the system. - -@item -If a single source package corresponds to several binary packages, there -should usually be a @file{debian.rules} file with a single @file{binary} -target that builds all the binary packages involved and move all packages -to the parent directory of that containing the source package. - -In this case, you should choose binary package names which are meant to -make clear the close relationship between the binary packages and which -source package the binary packages came from (for example, the -@file{texinfo} source package build two binary packages: @file{texidoc} -and @file{texinfo}). You should place the appropriate binary package -name in the @file{Package} field of the control file (not the source -package name), and you should consider whether the other binary packages -that come from the same source tree should be mentioned in the -@file{Depends}, @file{Recommends} or @file{Suggests} fields. You -should put the source package name in the @file{Source} field. - -You should retain the source package version numbering in the -@file{Version} field---the version number should be the same for the -Debianised source tree and all the binary packages generated from it. -See below for details of version numbers. -@end itemize - - - -@node Control Files, , Binary Package, Top -@unnumbered Control Files - - Each binary package contains, in addition to the files that comprise -the actual package, a set of text files that control how @file{dpkg} -installs, configures, upgrades, removes, etc. the package. These files -are called @dfn{control files}. When creating the package, the control -files should placed in a directory called @file{DEBIAN}, as described -earlier (@pxref{Binary Package}, for further information). - -The control information files are: - -@table @code -@item control -The master package control information file. -@item conffiles -A list of package configuration files. -@item preinst -The package pre-installation script. -@item postinst -The package post-installation script. -@item prerm -The package pre-removal script. -@item postrm -The package post-removal script. -@end table - - Of these, only @file{control} is required. The various installation -scripts, and the configuration files list, will only be used if they are -present. - -@menu -* control:: -* conffiles:: -* Installation and Removal Scripts:: -* Dependencies and Conflicts:: -* Package Classification Fields:: -@end menu - -@node control, conffiles, Control Files, Control Files -@unnumberedsec control - - The @file{control} file contains a number of fields. Each field -begins with a field name, such as @file{Package} or @file{Version} -(case insensitive), followed by a colon and optionally some spaces or -tabs (a single space is conventional). Then comes the body of the -field, which may be several lines long; each continuation line must -start with at least one space or tab. (These are the same rules as -apply to RFC822 mail headers.) Blank lines are not permitted in the -control file. - - The required fields in the control file are the following: - -@table @code -@item Package -The name of the package. -@item Description -The description of the package. -@item Maintainer -The name and e-mail address of the maintainer of the package. -@item Version -The version number in the format -@code{<@i{original_version}>-<@i{debian_revision}>}. -@end table - - Each field has a particular format and meaning for the package -installation tools. - -The value of @file{Package} should be the name of the package. -Package names must start with an alphanumeric, must be at least two -characters, and may contain only alphanumerics and the characters -- + . @@ : = % _ (that is, hyphen, plus, stop, at, colon, equals, -percent and underscore). They are not case sensitive. - - The @code{Maintainer} field should be in the form - -@smallexample -Joe J. Bloggs -@end smallexample - -@noindent Note that this will not be useable as an email address if -the name given contains full stop characters, because of a silly -restriction in the Internet mail standards. If you want to use this -as an email address in a program you should check for full stops and -change the string to the form @code{jbloggs@@foo.com (Joe J. Bloggs)} -if you find any. - - The @code{Version} field should be the version number of the -package. For most packages which are not written specifically for -Debian, this should be in the form - -@smallexample -Version: <@i{original_version}>-<@i{debian_revision}> -@end smallexample - -@noindent where @file{<@i{original_version}>} is the original package -version number in whatever form the original package uses and -@file{<@i{debian_revision}>} indicates which ``debianisation'' this is -(this should usually be a plain number or perhaps a two numbers -separated by a full stop, and should be incremented each time the -package is changed or updated). - - Packages which are written specifically for Debian do not have a -@i{debian_revision}, and their version number should simply be -@i{version} (which should not contain any hyphens, to avoid -confusion). - - There is an ordering imposed on version numbers, described in -@file{version-ordering.txt}. This ordering is designed to `do the right -thing' in most circumstances; if your package has an version number in -an unusual format you may need to reformat it somewhat to get the -ordering right. This is important because @file{dpkg} is (for example) -reluctant to downgrade packages. - - The optional fields in the control file are the following: - -@table @code -@item Depends -The names of prerequisite packages. -@item Recommends -The names of related, recommended packages. -@item Suggests -The names of related, optional packages. -@item Conflicts -The names of packages which conflict with this package. -@item Provides -The names of virtual packages which this package provides. -@item Priority -The `priority' of the package, as shown and used by @file{dselect}. -@item Section -The `section' of the package, as shown and used by @file{dselect}, and -used as a location for the package in the distribution. -@item Essential -A boolean field used by the base packages. -@end table - -@noindent See below for details of the semantics and syntax of these -fields. Most packages will need at least a @code{Depends} field. - - An example of a @file{control} file would be: - -@example - Package: smail - Version: 3.1.29.1-13 - Maintainer: Ian Jackson - Recommends: pine | mailx | elm | emacs | mail-user-agent - Suggests: metamail - Depends: cron, libc5 - Conflicts: sendmail - Provides: mail-transport-agent - Description: Electronic mail transport system. - Smail is the recommended mail transport agent (MTA) for Debian. - . - An MTA is the innards of the mail system - it takes messages from - user-friendly mailer programs and arranges for them to be delivered - locally or passed on to other systems as required. - . - In order to make use of it you must have one or more user level - mailreader programs such as elm, pine, mailx or Emacs (which has Rmail - and VM as mailreaders) installed. If you wish to send messages other - than just to other users of your system you must also have appropriate - networking support, in the form of IP or UUCP. -@end example - - In this case, @file{mail-user-agent} is a virtual package -representing any user mailer program; the actual package names -@file{pine} is quoted for the reasons described in -@file{dependency-ordering.txt}, and the others because older versions -of those packages do not have the appropriate @file{Provides} field. - -@node conffiles, Installation and Removal Scripts, control, Control Files -@unnumberedsec conffiles - - The contents of @file{conffiles} is simply a list of configuration -files in the package. When installing the package, @file{dpkg} uses -an intelligent method to update these files. This will ensure that -package-specific configuration files are not overwritten when a package -is upgraded, unless the user wishes the installation tools to do so. - - Typically, files listed in conffiles are package-specific -configuration files, which (according to the Linux Filesystem Standard) -are stored in @file{/etc}. For example, the @code{sendmail} package may -contain the file @file{/etc/sendmail.cf}, which we do not wish to -overwrite automatically when the user upgrades the sendmail package. -Only those files listed in @file{DEBIAN/conffiles} will be updated -intelligently when a package is upgraded; all other files in the package -will be overwritten by the upgrade process. - - Configuration files which will be functional as shipped and will -probably need little or no local editing should simply be listed the -@file{conffiles} file; in this case you need read no further. - - For packages whose configuration files will need modification on -most systems there are two sensible approaches. Which one is chosen -depends on how hard the configuration problem is and how much time the -package maintainer has available. - - One option is for you to ship a minimal `best-effort' file in -@file{/etc}, and list the file in @file{conffiles}. This will mean that -the user will have to go and edit the file themselves to get the package -to work properly, of course. The next time they upgrade the package, if -you haven't changed the file version, their old file will be left in -place. If you have modified your version then the user will get a -prompt asking them which version of the file they want, theirs or yours. -They will then usually have to resolve the discrepancies manually. - - The other option is to be preferred, if you can do it: don't put a -copy of the configuration file in the package at all. Instead, you -check in the postinst whether the file exists, and if it doesn't you -prompt the user for the information you need to create a good one. This -is obviously harder work. - - You also have to remember that you will have to keep up with your -package's changes: if you discover a bug in the program which generates -the configuration file, or if the format of the file changes from one -version to the next, you will have to arrange for the postinst script to -do something sensible---usually this will mean editing the installed -configuration file to remove the problem or change the syntax. You will -have to do this very carefully, since the user may have changed the -file, perhaps to fix the very problem that your script is trying to deal -with---you will have to detect these situations and deal with them -correctly. - - If you do go down this route it's probably a good idea to make the -program that generates the configuration file(s) a separate program in -@file{/usr/sbin}, by convention called @i{package}@code{config}, and -then run that if appropriate from the post-installation script. The -@i{package}@code{config} program should not unquestioningly overwrite an -existing configuration---if its mode of operation is geared towards -setting up a package for the first time (rather than any arbitrary -reconfiguration later) you should have it check whether the -configuration already exists, and require a @code{--force} flag to -overwrite it. - - @file{conffiles} should almost certainly list all the files contained -in your package in the @file{/etc} directory. There may also be other -files somewhere that the user is expected to edit, which should also be -included. Note, however, that the FSSTND specifies that configuration -files must be in @file{/etc}. No Debian package should contain -configuration files in @file{/usr/etc}, and all programs should refer to -configuration files in @file{/etc}. - -@noindent For example, the TCP/IP package might use a conffiles which contains - -@example - /etc/init.d/netbase - /etc/gateways - /etc/protocols - /etc/services - /etc/hosts.allow - /etc/hosts.deny - /etc/rpc -@end example - -@noindent and so on; the files - -@example - /etc/hosts - /etc/inetd.conf - /etc/host.conf - /etc/networks - /etc/resolv.conf -@end example - -@noindent might be generated by an interactive configuration program, -and would then not be included in the package or listed in the -@file{conffiles}. - -@node Installation and Removal Scripts, Dependencies and Conflicts, conffiles, Control Files -@unnumberedsec Installation and Removal Scripts - - The scripts @file{preinst}, @file{postinst}, @file{prerm}, and -@file{postrm} are optional (Bash or Perl) scripts. As the names -would indicate, if these scripts exist, they will be executed before -installing the package, after installation, before package removal, -and after removal, respectively. - - They are given arguments which indicate the precise situation and -action being performed---see @file{maintainer-script-args.txt} for -details of exactly when each of the scripts is invoked and what its -arguments are. Extra arguments and situations may be added later, so -you should not test the number of arguments to your script to determine -the situation, and you should choose the sense of your `if it is this -then do this otherwise do that' tests carefully. - - These scripts can be used to perform any site-specific package -configuration. - - Because the scripts will be exectued by the dpkg front-end, it is -guaranteed that the scripts will be executed interactively. User input -from the scripts should be read from standard input, not the user's -terminal. Similarly, output should be sent to standard output. - - If your maintainer scripts need to prompt for passwords and/or do -@i{full-screen} interaction should do these things to and from -@file{/dev/tty}, since @file{dpkg} will at some point redirect scripts' -standard input and output so that it can log the installation process. -Likewise, because these scripts may be executed with standard output -redirected into a pipe for logging purposes, Perl scripts should set -unbuffered output by setting @code{$|=1} so that the output is printed -immediately rather than being buffered. - - The scripts must be idempotent, and they must clean up after -themselves properly. Ie, they must do the right thing if run multiple -times, even if previous runs failed halfway through. This is so that if -any errors occur, or if the @file{dpkg} run is interrupted, the user can -recover by rerunning @file{dpkg}, and/or by upgrading to a new version -and then rerunning the failed operation. - - These scripts should avoid producing output which it is unnecessary -for the user to see and should rely on @file{dpkg} to stave off boredom -on the part of a user installing many packages. This means, amongst -other things, using the @file{--quiet} option on @file{install-info}. - - Packages should try to minimise the amount of prompting they need to -do, and they should ensure that the user will only every be asked each -question once. This means that packages should try to use appropriate -shared configuration files (such as @file{/etc/papersize} and -@file{/etc/news/server}), rather than each prompting for their own list -of required pieces of information. - - It also means that an upgrade should not ask the same questions -again, unless the user has used @code{dpkg --purge} to remove the -package's configuration. The answers to configuration questions should -be stored in an appropriate place in @file{/etc} so that the user can -modify them, and how this has been done should be documented. - - If a package has a vitally important piece of information to pass to -the user (such as "don't run me as I am, you must edit the following -configuration files first or you risk your system emitting -badly-formatted messages"), it should display this in the -@file{postinst} script and prompt the user to hit Return to acknowledge -the message. Copyright messages do not count as vitally important (they -belong in @file{/usr/doc/copyright}; neither do instructions on how to -use a program (these should be in on line documentation, where all the -users can see them). - - They should return a zero exit status for success, or a nonzero one -for failure. Note that if a script is a @code{#!/bin/sh} script it -should probably start with @code{set -e}, to avoid continuing after -errors---see @file{bash}(1) for details. Perl scripts should check for -errors when making calls such as @code{open}, @code{print}, -@code{close}, @code{rename} and @code{system}. - - If these scripts exist they should be left in the @file{DEBIAN} -directory with execute permission enabled and should contain an -appropriate @code{#!} line, such as @code{#!/bin/bash} for a -@code{bash} script or @code{#!/bin/perl} for a Perl script (see -above). - -@node Dependencies and Conflicts, Package Classification Fields, Installation and Removal Scripts, Control Files -@unnumberedsec Conflicts, Depends, Suggests, Recommends and Provides - - The @file{Depends} field lists packages that are required for this -package to provide a significant amount of functionality. The package -maintenance software will not allow a package to be installed without -also installing packages listed in its @code{Depends} field, and will -run the @code{postinst} scripts of packages listed in @code{Depends} -fields before those of the packages which depend on them, and run the -@code{prerm} scripts before. - - Packages containing dynamically-linked executable binaries (this -includes almost all C programs) should include a @file{Depends} field -which mentions the shared C library required for the program to run. -For a.out binaries linked against @file{libc.so.4} the relevant package -name is @file{libc}; for ELF binaries linked against @file{libc.so.5} -the relevant package name is @file{libc5}. - - The @code{Recommends} field lists packages that would be found -together with this one in all but unusual installations. The user-level -package maintenance program @file{dselect} will warn the user if they -select a package without those listed in its @code{Recommends} field. -Note that @code{Recommends} fields don't currently have any implications -for the order in which the maintainer scripts are run. - - The @code{Suggests} field lists packages that are related to this one -and can perhaps enhance its usefulness, but without which installing -this package is perfectly reasonable. The package maintenance software -will not moan at the user for not selecting @code{Suggests} related -packages, but may use the information in the @code{Suggests} field to -assist the user during package selection. - - The syntax of @code{Depends}, @code{Recommends} and @code{Suggests} -is a list of groups of alternative packages. Each group is a list of -packages separated by vertical bar (or `pipe') symbols, @code{|}. The -groups are separated by commas. Each package is a package name -optionally followed by a version number specification in parentheses. A -version number may start with a @code{>=}, in which case that version or -any later will match, or @code{<=} for that version or any earlier -version. A version number starting with a @code{>>} or @code{<<} will -respectively match any later or earlier version. If a version number or -a version number starting with @code{=} is specified an exact match is -required. Commas are to be read as `AND', and pipes as `OR', with pipes -binding more tightly. - - Versions of dpkg before 1.0.9 used @code{<} and @code{>} for -@code{<=} and @code{>=} (these are still supported for backward -compatibility), and did not support @code{<<} and @code{>>}. - - The @code{Conflicts} field lists packages that conflict with this -one, for example by containing files with the same names (an example -would be Smail vs. Sendmail). The package maintenance software will not -allow conflicting packages to be installed. Two conflicting packages -should each include a @code{Conflicts} line mentioning the other. - - The syntax of @code{Conflicts} is a list of package names (with -optional version numbers), separated by commas (and optional -whitespace). In the @code{Conflicts} field the comma should be read as -`OR'. - - The @code{Provides} field lists the names of any `virtual packages' -of which this packages is to be considered an instantiation. Virtual -packages are used to allow packages to refer to a service they require -(such as the availability of @file{/usr/sbin/sendmail}) without having -to know the names of all the relevant packages. The virtual package -names defined in @code{Provides} fields may be used in other packages' -@code{Depends}, @code{Recommends}, @code{Suggests} and @code{Conflicts} -fields. For more information about how to use virtual packages and -which virtual package names to use read @file{virtual-dependencies.txt} -and @file{virtual-package-names-list.text}. - - The syntax of @code{Provides} is a list of package names separated by -commas (and optional whitespace). - -@node Package Classification Fields, , Dependencies and Conflicts, Control Files -@unnumberedsec Priority, Section and Essential - - The @code{Priority} and @code{Section} fields are used by -@file{dselect} when displaying the list of packages to the user. There -is no need to put them into a package, since these are usually set by -the distribution maintainers in the @file{Packages} file. - - However, if a user installs a package which is not part of the -standard distribution, or without downloading and updating from a new -@file{Packages} file, the information about the priority and section of -a package will be absent, and the @file{dselect} package listing will -have the package listed under `unclassified'. It is permissible for a -package to include @code{Section} or @code{Priority} fields to improve -this; however, if you do this you should make sure you keep the -information up to date so that users are not shown conflicting -information. The @code{Section} field can also be used by the -distribution maintainers as a suggestion about which section you think -is most appropriate for your package. - - The @code{Essential} field should only appear in packages in the -installation's base system. If it is set to @code{yes} then @file{dpkg} -will not remove the package even if asked to, and will make certain -minor modifications to its installation procedures. The only other -legal value is @code{no}, which is equivalent to the absence of the -field. - -@bye - -@c local variables: -@c kept-new-versions: 100 -@c version-control: t -@c end: diff --git a/doc/guidelines.texi.rej b/doc/guidelines.texi.rej deleted file mode 100644 index 15354007..00000000 --- a/doc/guidelines.texi.rej +++ /dev/null @@ -1,33 +0,0 @@ -*************** -*** 376,390 **** - Generally the following compilation parameters should be used: - - @display -- CC = gcc -- CFLAGS = -O2 -- LDFLAGS = -s (and -N, if appropriate; see below) - @end display - - All installed binaries should be stripped, hence @code{-s}. @code{-N} - should only be used on binaries that are very small (less than 8K with - the @code{-N} option, roughly) and are not likely to have multiple -- instances in memory. Do not use @code{-N} on daemons, no matter how - small they are. - - It is up to the package maintainer to decide what compilation options ---- 383,397 ---- - Generally the following compilation parameters should be used: - - @display -+ CC = gcc -+ CFLAGS = -O2 -+ LDFLAGS = -s (and -N, if appropriate; see below) - @end display - - All installed binaries should be stripped, hence @code{-s}. @code{-N} - should only be used on binaries that are very small (less than 8K with - the @code{-N} option, roughly) and are not likely to have multiple -+ instances in memory. Don't use @code{-N} on daemons, no matter how - small they are. - - It is up to the package maintainer to decide what compilation options diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c index 7be355a8..3eef94f9 100644 --- a/dpkg-deb/build.c +++ b/dpkg-deb/build.c @@ -43,12 +43,12 @@ # define S_ISLNK(mode) ((mode&0xF000) == S_IFLNK) #endif -static void checkversion(const char *vstring, const char *fieldname, int *errs) { +static void checkversion(const char *vstring, const char *valuename, int *errs) { const char *p; if (!vstring || !*vstring) return; for (p=vstring; *p; p++) if (isdigit(*p)) return; - fprintf(stderr, BACKEND " - error: %s field (`%s') doesn't contain any digits\n", - fieldname, vstring); + fprintf(stderr, BACKEND " - error: %s (`%s') doesn't contain any digits\n", + valuename, vstring); (*errs)++; } @@ -107,8 +107,8 @@ void do_build(const char *const *argv) { controlfile, field->name); warns++; } - checkversion(checkedinfo->available.version,"Version",&errs); - checkversion(checkedinfo->available.revision,"Revision",&errs); + checkversion(checkedinfo->available.version.version,"(upstream) version",&errs); + checkversion(checkedinfo->available.version.revision,"Debian revision",&errs); if (errs) ohshit("%d errors in control file",errs); printf(BACKEND ": building package `%s' in `%s'.\n", checkedinfo->name, debar); diff --git a/dpkg-deb/main.c b/dpkg-deb/main.c index 0804ac72..ee2321aa 100644 --- a/dpkg-deb/main.c +++ b/dpkg-deb/main.c @@ -40,12 +40,12 @@ #include "dpkg-deb.h" static void printversion(void) { - if (!fputs("Debian GNU/Linux `" BACKEND "' package archive backend " + if (!fputs("Debian Linux `" BACKEND "' package archive backend " "version " DPKG_VERSION_ARCH ".\n" - "Copyright (C) 1994,1995 Ian Jackson. This is free software; see the\n" + "Copyright (C) 1994-1996 Ian Jackson. This is free software; see the\n" "GNU General Public Licence version 2 or later for copying conditions.\n" "There is NO warranty. See dpkg-deb --licence for details.\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } static void usage(void) { @@ -69,7 +69,7 @@ Options: -D for debugging output; --old or --new controls archive format;\n\ Use `" DPKG "' to install and remove packages from your system, or\n\ `" DSELECT "' for user-friendly package management. Packages unpacked\n\ using `" BACKEND " --extract' will be incorrectly installed !\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } const char thisname[]= BACKEND; diff --git a/dselect/helpmsgs.src b/dselect/helpmsgs.src index 2bcf1494..db1dd5a1 100644 --- a/dselect/helpmsgs.src +++ b/dselect/helpmsgs.src @@ -10,18 +10,18 @@ Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards: B, Left-arrow F, Right-arrow pan display by 1/3 screen ^b ^f pan display by 1 character -Package states - selection: Package states - hold flag: - +, Insert select package(s) H put package(s) `on hold' - -, Delete deselect package(s) G `go' - take off hold - _ deselect, purge configuration +Selection for later processing: + +, Insert install or upgrade =, H hold in present state + -, Delete remove :, G unhold: upgrade or leave uninstalled + _ remove & purge config Miscellaneous: -Quit, exit, overwrite (note capitals!): ? request help (also Help, F1) - Return Confirm and quit (check dependencies) i toggle/cycle info displays - Q Confirm and quit (override dep.s) o cycle through sort orders - X, Esc eXit, abandoning any changes made v toggle verbose status display - R Revert to state before this list ^l redraw display - U set all to sUggested state / search (hit Return to cancel) - D set all to Directly selected state \\ repeat last search +Quit, exit, overwrite (note capitals!): ?, F1 request help (also Help) + Return Confirm, quit (check dependencies) i toggle/cycle info displays + Q Confirm, quit (override dep.s) o, O cycle through sort options + X, Esc eXit, abandoning any changes made v, V change status display opts + R Revert to state before this list ^l redraw display + U set all to sUggested state / search (Return to cancel) + D set all to Directly selected state ) \\ repeat last search @@@ mainintro Introduction to package list @@ -174,6 +174,6 @@ Quit: Miscellaneous: ?, Help, F1 request help - ^l redraw display - / search (just return to cancel) - \\ repeat last search + ^l redraw display + / search (just return to cancel) + \\ repeat last search diff --git a/dselect/main.cc b/dselect/main.cc index e65f6352..21535d1a 100644 --- a/dselect/main.cc +++ b/dselect/main.cc @@ -75,7 +75,7 @@ static const menuentry menuentries[]= { }; static const char programdesc[]= - "Debian GNU/Linux `" DSELECT "' package handling frontend."; + "Debian Linux `" DSELECT "' package handling frontend."; static const char copyrightstring[]= "Version " DPKG_VERSION_ARCH ". Copyright (C) 1994,1995 Ian Jackson. This is\n" @@ -83,7 +83,7 @@ static const char copyrightstring[]= "copying conditions. There is NO warranty. See dselect --licence for details.\n"; static void printversion(void) { - if (fprintf(stderr,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stderr"); + if (fprintf(stdout,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stdout"); } static void usage(void) { @@ -93,7 +93,7 @@ static void usage(void) { "Options: --admindir (default is /var/lib/dpkg)\n" " --help --version --licence --debug | -D | -D\n" "Actions: access update select install config remove quit menu\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } /* These are called by C code, so need to have C calling convention */ @@ -167,7 +167,9 @@ extern void operator delete(void *p) { urqresult urq_list(void) { readwrite= modstatdb_init(admindir, - msdbrw_writeifposs|msdbrw_availablepreferversion); + // Why do I need this cast ?? + (modstatdb_rw)(msdbrw_writeifposs| + msdbrw_availablepreferversion)); curseson(); diff --git a/dselect/methparse.cc b/dselect/methparse.cc index 02e51b41..ffa280ee 100644 --- a/dselect/methparse.cc +++ b/dselect/methparse.cc @@ -183,7 +183,8 @@ void readmethods(const char *pathbase, option **optionspp, int *nread) { if (fstat(fileno(descfile),&stab)) ohshite("unable to stat option description file `%.250s'",pathbuf); opt->description= new char[stab.st_size+1]; errno=0; - if (fread(opt->description,1,stab.st_size+1,descfile) != stab.st_size) + unsigned long filelen= stab.st_size; + if (fread(opt->description,1,stab.st_size+1,descfile) != filelen) ohshite("failed to read option description file `%.250s'",pathbuf); opt->description[stab.st_size]= 0; if (ferror(descfile)) diff --git a/dselect/pkgcmds.cc b/dselect/pkgcmds.cc index bc728af2..de8aa308 100644 --- a/dselect/pkgcmds.cc +++ b/dselect/pkgcmds.cc @@ -73,14 +73,26 @@ void packagelist::movecursorafter(int ncursor) { refreshlist(); redrawthisstate(); } -void packagelist::setwant(pkginfo::pkgwant nw) { +pkginfo::pkgwant packagelist::reallywant(pkginfo::pkgwant nwarg, + struct perpackagestate *pkgstate) { + if (nwarg != pkginfo::want_sentinel) return nwarg; + pkginfo::pkgstatus status= pkgstate->pkg->status; + if (status == pkginfo::stat_notinstalled) return pkginfo::want_purge; + if (status == pkginfo::stat_configfiles) return pkginfo::want_deinstall; + return pkginfo::want_install; +} + +void packagelist::setwant(pkginfo::pkgwant nwarg) { int index, top, bot; + pkginfo::pkgwant nw; if (!readwrite) { beep(); return; } if (recursive) { redrawitemsrange(cursorline,cursorline+1); - table[cursorline]->selected= nw; + nw= reallywant(nwarg,table[cursorline]); + nw= nwarg != pkginfo::want_sentinel ? nwarg : + table[cursorline]->selected= reallywant(nwarg,table[cursorline]); redraw1item(cursorline); top= cursorline; bot= cursorline+1; @@ -89,9 +101,11 @@ void packagelist::setwant(pkginfo::pkgwant nw) { affectedrange(&top,&bot); for (index= top; index < bot; index++) { - if (!table[index]->pkg->name || - table[index]->selected == nw || - table[index]->selected == pkginfo::want_purge && nw == pkginfo::want_deinstall) + if (!table[index]->pkg->name) continue; + nw= reallywant(nwarg,table[index]); + if (table[index]->selected == nw || + (table[index]->selected == pkginfo::want_purge && + nw == pkginfo::want_deinstall)) continue; sub->add(table[index]->pkg,nw); } @@ -104,33 +118,36 @@ void packagelist::setwant(pkginfo::pkgwant nw) { } void packagelist::kd_select() { setwant(pkginfo::want_install); } +void packagelist::kd_hold() { setwant(pkginfo::want_hold); } void packagelist::kd_deselect() { setwant(pkginfo::want_deinstall); } +void packagelist::kd_unhold() { setwant(pkginfo::want_sentinel); } void packagelist::kd_purge() { setwant(pkginfo::want_purge); } -void packagelist::sethold(int hold) { - int top, bot, index; - - if (!readwrite) { beep(); return; } - - affectedrange(&top,&bot); - for (index= top; index < bot; index++) { - // Sorry about the contortions, but GCC produces a silly warning otherwise - unsigned int neweflag= table[index]->pkg->eflag; - if (hold) neweflag |= pkginfo::eflagf_hold; - else neweflag &= ~pkginfo::eflagf_hold; - table[index]->pkg->eflag= (enum pkginfo::pkgeflag)neweflag; - redraw1item(index); - } - movecursorafter(bot); +int would_like_to_install(pkginfo::pkgwant wantvalue, pkginfo *pkg) { + /* Returns: 1 for yes, 0 for no, -1 for if they want to preserve an error condition. */ + if (wantvalue == pkginfo::want_install) return 1; + if (wantvalue != pkginfo::want_hold) return 0; + if (pkg->status == pkginfo::stat_installed) return 1; + if (pkg->status == pkginfo::stat_notinstalled || + pkg->status == pkginfo::stat_configfiles) return 0; + return -1; } - -void packagelist::kd_hold() { sethold(1); } -void packagelist::kd_unhold() { sethold(0); } - + const char *packagelist::itemname(int index) { return table[index]->pkg->name; } +void packagelist::kd_swapstatorder() { + if (sortorder == so_unsorted) return; + switch (statsortorder) { + case sso_avail: statsortorder= sso_state; break; + case sso_state: statsortorder= sso_unsorted; break; + case sso_unsorted: statsortorder= sso_avail; break; + default: internerr("unknown statsort in kd_swapstatorder"); + } + resortredisplay(); +} + void packagelist::kd_swaporder() { switch (sortorder) { case so_priority: sortorder= so_section; break; @@ -139,6 +156,10 @@ void packagelist::kd_swaporder() { case so_unsorted: return; default: internerr("unknown sort in kd_swaporder"); } + resortredisplay(); +} + +void packagelist::resortredisplay() { const char *oldname= table[cursorline]->pkg->name; sortmakeheads(); int newcursor; @@ -164,6 +185,22 @@ void packagelist::kd_swaporder() { refreshlist(); } +void packagelist::kd_versiondisplay() { + switch (versiondisplayopt) { + case vdo_both: versiondisplayopt= vdo_none; break; + case vdo_none: versiondisplayopt= vdo_available; break; + case vdo_available: versiondisplayopt= vdo_both; break; + default: internerr("unknown versiondisplayopt in kd_versiondisplay"); + } + setwidths(); + leftofscreen= 0; + ldrawnstart= ldrawnend= -1; + redrawtitle(); + redrawcolheads(); + redrawitemsrange(topofscreen,lesserint(topofscreen+list_height,nitems)); + refreshlist(); +} + void packagelist::kd_verbose() { verbose= !verbose; setwidths(); @@ -208,7 +245,6 @@ void packagelist::kd_revertsuggest() { } /* fixme: configurable purge/deselect */ -/* fixme: un-hold things */ void packagelist::kd_info() { currentinfo++; diff --git a/dselect/pkgdepcon.cc b/dselect/pkgdepcon.cc index 6026a5db..9740131f 100644 --- a/dselect/pkgdepcon.cc +++ b/dselect/pkgdepcon.cc @@ -120,12 +120,12 @@ static int dep_update_best_to_change_stop(perpackagestate *& best, pkginfo *tryt int packagelist::deselect_one_of(pkginfo *per, pkginfo *ped, dependency *display) { perpackagestate *er= per->clientdata; perpackagestate *ed= ped->clientdata; - - if (!er || er->selected != pkginfo::want_install || - !ed || ed->selected != pkginfo::want_install) return 0; + + if (!er || !would_like_to_install(er->selected,per) || + !ed || !would_like_to_install(ed->selected,ped)) return 0; add(display,dp_must); - + er= per->clientdata; // these can be changed by add ed= ped->clientdata; @@ -134,9 +134,11 @@ int packagelist::deselect_one_of(pkginfo *per, pkginfo *ped, dependency *display this, er->pkg->name, er->spriority, ed->pkg->name, ed->spriority, display); perpackagestate *best; - if (er->spriority < ed->spriority) best= er; // We'd rather change the - else if (er->spriority > ed->spriority) best= ed; // one with the lowest priority. - + + if (per->eflag & pkginfo::eflagf_reinstreq) best= ed; // Try not keep packages + else if (ped->eflag & pkginfo::eflagf_reinstreq) best= er; // needing reinstallation + else if (er->spriority < ed->spriority) best= er; // We'd rather change the + else if (er->spriority > ed->spriority) best= ed; // one with the lowest priority. else if (er->pkg->priority > er->pkg->priority) best= er; // ... failing that the one with else if (er->pkg->priority < // the highest priority @@ -276,10 +278,7 @@ int deppossatisfied(deppossi *possi) { // and therefore OK, or a version must have been specified, // in which case we don't need to look at the rest anyway. if (possi->verrel == deppossi::dvr_none) return 1; - int r= versioncompare(possi->ed->available.version, - possi->ed->available.revision, - possi->version, - possi->revision); + int r= versioncompare(&possi->ed->available.version,&possi->version); switch (possi->verrel) { case deppossi::dvr_earlierequal: return r <= 0; case deppossi::dvr_laterequal: return r >= 0; @@ -296,7 +295,8 @@ int deppossatisfied(deppossi *possi) { provider= provider->nextrev) { if (provider->up->type != dep_provides) continue; if (provider->up->up->clientdata && - provider->up->up->clientdata->selected == pkginfo::want_install) + would_like_to_install(provider->up->up->clientdata->selected, + provider->up->up) == 1) return 1; } return 0; diff --git a/dselect/pkgdisplay.cc b/dselect/pkgdisplay.cc index 4704e217..bedac26c 100644 --- a/dselect/pkgdisplay.cc +++ b/dselect/pkgdisplay.cc @@ -35,9 +35,8 @@ extern "C" { /* These MUST be in the same order as the corresponding enums in dpkg-db.h */ const char - *const wantstrings[]= { "new package", "selected", "deselected", "purge", 0 }, - *const holdstrings[]= { "", "on hold", "REINSTALL", - "hold,REINSTALL", 0 }, + *const wantstrings[]= { "new package", "selected", "hold", "remove", "purge", 0 }, + *const eflagstrings[]= { "", "REINSTALL", 0 }, *const statusstrings[]= { "not installed", "unpacked (not set up)", "failed config", "installed", "half installed", "removed (configs remain)", 0 }, @@ -49,9 +48,34 @@ const char *const priorityabbrevs[]= { "Req", "Imp", "Std", "Rec", "Opt", "Xtr", "Ctb", "bUG", "?" }; -const char statuschars[]= " uF*H-"; -const char holdchars[]= " hRX"; -const char wantchars[]= "n*-_"; +const char statuschars[]= " UF*H-"; +const char eflagchars[]= " R?#"; +const char wantchars[]= "n*=-_"; + +/* These MUST be in the same order as the corresponding enums in pkglist.h */ +const char + *const ssaabbrevs[]= { "Broken", + "New", + "Updated", + "Obsolete/local", + "Up-to-date", + "Available" }, + *const ssastrings[]= { "Brokenly installed packages", + "Newly available packages", + "Updated packages (newer version is available)", + "Obsolete and local packages present on system", + "Up to date installed packages", + "Available packages (not currently installed)" }; + +const char + *const sssstrings[]= { "Brokenly installed packages", + "Installed packages", + "Removed packages (configuration still present)", + "Purged packages and those never installed" }, + *const sssabbrevs[]= { "Broken", + "Installed", + "Removed", + "Purged" }; static int maximumstring(const char *const *array) { int maxlen= 0; @@ -74,7 +98,7 @@ void packagelist::setwidths() { status_want_width= maximumstring(wantstrings); status_width= status_hold_width+status_status_width+status_want_width*2+3; priority_width= 8; - package_width= 16; + package_width= 16; } else { status_width= 4; priority_width= 3; @@ -94,8 +118,31 @@ void packagelist::setwidths() { package_column= section_column + section_width + gap_width; } - description_column= package_column + package_width + gap_width; - + int versiondescriptioncolumn= package_column + package_width + gap_width; + + switch (versiondisplayopt) { + case vdo_none: + versioninstalled_column= versioninstalled_width= 0; + versionavailable_column= versionavailable_width= 0; + description_column= versiondescriptioncolumn; + break; + case vdo_available: + versioninstalled_column= versioninstalled_width= 0; + versionavailable_column= versiondescriptioncolumn; + versionavailable_width= 11; + description_column= versionavailable_column + versionavailable_width + gap_width; + break; + case vdo_both: + versioninstalled_column= versiondescriptioncolumn; + versioninstalled_width= 11; + versionavailable_column= versioninstalled_column + versioninstalled_width +gap_width; + versionavailable_width= versioninstalled_width; + description_column= versionavailable_column + versionavailable_width + gap_width; + break; + default: + internerr("unknown versiondisplayopt in setwidths"); + } + total_width= TOTAL_LIST_WIDTH; description_width= total_width - description_column; } @@ -114,12 +161,50 @@ void packagelist::redrawtitle() { if (x < xmax) { switch (sortorder) { case so_section: - waddnstr(titlewin, " (by section)", xmax-x); + switch (statsortorder) { + case sso_unsorted: + waddnstr(titlewin, " (by section)", xmax-x); + break; + case sso_avail: + waddnstr(titlewin, " (avail., section)", xmax-x); + break; + case sso_state: + waddnstr(titlewin, " (status, section)", xmax-x); + break; + default: + internerr("bad statsort in redrawtitle/so_section"); + } break; case so_priority: - waddnstr(titlewin, " (by priority)", xmax-x); + switch (statsortorder) { + case sso_unsorted: + waddnstr(titlewin, " (by priority)", xmax-x); + break; + case sso_avail: + waddnstr(titlewin, " (avail., priority)", xmax-x); + break; + case sso_state: + waddnstr(titlewin, " (status, priority)", xmax-x); + break; + default: + internerr("bad statsort in redrawtitle/so_priority"); + } break; case so_alpha: + switch (statsortorder) { + case sso_unsorted: + waddnstr(titlewin, " (alphabetically)", xmax-x); + break; + case sso_avail: + waddnstr(titlewin, " (by availability)", xmax-x); + break; + case sso_state: + waddnstr(titlewin, " (by status)", xmax-x); + break; + default: + internerr("bad statsort in redrawtitle/so_priority"); + } + break; waddnstr(titlewin, " (alphabetically)", xmax-x); break; case so_unsorted: diff --git a/dselect/pkgkeys.cc b/dselect/pkgkeys.cc index 41a9bfb4..bea8d6a3 100644 --- a/dselect/pkgkeys.cc +++ b/dselect/pkgkeys.cc @@ -34,110 +34,115 @@ extern "C" { #include "bindings.h" const keybindings::interpretation packagelist_kinterps[] = { - { "up", 0, packagelist::kd_up, qa_noquit }, - { "down", 0, packagelist::kd_down, qa_noquit }, - { "top", 0, packagelist::kd_top, qa_noquit }, - { "bottom", 0, packagelist::kd_bottom, qa_noquit }, - { "scrollon", 0, packagelist::kd_scrollon, qa_noquit }, - { "scrollback", 0, packagelist::kd_scrollback, qa_noquit }, - { "iscrollon", 0, packagelist::kd_iscrollon, qa_noquit }, - { "iscrollback", 0, packagelist::kd_iscrollback, qa_noquit }, - { "scrollon1", 0, packagelist::kd_scrollon1, qa_noquit }, - { "scrollback1", 0, packagelist::kd_scrollback1, qa_noquit }, - { "iscrollon1", 0, packagelist::kd_iscrollon1, qa_noquit }, - { "iscrollback1", 0, packagelist::kd_iscrollback1, qa_noquit }, - { "panon", 0, packagelist::kd_panon, qa_noquit }, - { "panback", 0, packagelist::kd_panback, qa_noquit }, - { "panon1", 0, packagelist::kd_panon1, qa_noquit }, - { "panback1", 0, packagelist::kd_panback1, qa_noquit }, - { "select", 0, packagelist::kd_select, qa_noquit }, - { "deselect", 0, packagelist::kd_deselect, qa_noquit }, - { "purge", 0, packagelist::kd_purge, qa_noquit }, - { "hold", 0, packagelist::kd_hold, qa_noquit }, - { "unhold", 0, packagelist::kd_unhold, qa_noquit }, - { "info", 0, packagelist::kd_info, qa_noquit }, - { "verbose", 0, packagelist::kd_verbose, qa_noquit }, - { "help", 0, packagelist::kd_help, qa_noquit }, - { "search", 0, packagelist::kd_search, qa_noquit }, - { "searchagain", 0, packagelist::kd_searchagain, qa_noquit }, - { "swaporder", 0, packagelist::kd_swaporder, qa_noquit }, - { "redraw", 0, packagelist::kd_redraw, qa_noquit }, - { "quitcheck", 0, packagelist::kd_quit_noop, qa_quitchecksave }, - { "quitrejectsug", 0, packagelist::kd_revertdirect, qa_quitnochecksave }, - { "quitnocheck", 0, packagelist::kd_quit_noop, qa_quitnochecksave }, - { "abortnocheck", 0, packagelist::kd_revert_abort, qa_quitnochecksave }, - { "revert", 0, packagelist::kd_revert_abort, qa_noquit }, - { "revertsuggest", 0, packagelist::kd_revertsuggest, qa_noquit }, - { "revertdirect", 0, packagelist::kd_revertdirect, qa_noquit }, - { 0, 0, qa_noquit } + { "up", 0, packagelist::kd_up, qa_noquit }, + { "down", 0, packagelist::kd_down, qa_noquit }, + { "top", 0, packagelist::kd_top, qa_noquit }, + { "bottom", 0, packagelist::kd_bottom, qa_noquit }, + { "scrollon", 0, packagelist::kd_scrollon, qa_noquit }, + { "scrollback", 0, packagelist::kd_scrollback, qa_noquit }, + { "iscrollon", 0, packagelist::kd_iscrollon, qa_noquit }, + { "iscrollback", 0, packagelist::kd_iscrollback, qa_noquit }, + { "scrollon1", 0, packagelist::kd_scrollon1, qa_noquit }, + { "scrollback1", 0, packagelist::kd_scrollback1, qa_noquit }, + { "iscrollon1", 0, packagelist::kd_iscrollon1, qa_noquit }, + { "iscrollback1", 0, packagelist::kd_iscrollback1, qa_noquit }, + { "panon", 0, packagelist::kd_panon, qa_noquit }, + { "panback", 0, packagelist::kd_panback, qa_noquit }, + { "panon1", 0, packagelist::kd_panon1, qa_noquit }, + { "panback1", 0, packagelist::kd_panback1, qa_noquit }, + { "select", 0, packagelist::kd_select, qa_noquit }, + { "deselect", 0, packagelist::kd_deselect, qa_noquit }, + { "purge", 0, packagelist::kd_purge, qa_noquit }, + { "hold", 0, packagelist::kd_hold, qa_noquit }, + { "unhold", 0, packagelist::kd_unhold, qa_noquit }, + { "info", 0, packagelist::kd_info, qa_noquit }, + { "verbose", 0, packagelist::kd_verbose, qa_noquit }, + { "versiondisplay", 0, packagelist::kd_versiondisplay, qa_noquit }, + { "help", 0, packagelist::kd_help, qa_noquit }, + { "search", 0, packagelist::kd_search, qa_noquit }, + { "searchagain", 0, packagelist::kd_searchagain, qa_noquit }, + { "swaporder", 0, packagelist::kd_swaporder, qa_noquit }, + { "swapstatorder", 0, packagelist::kd_swapstatorder, qa_noquit }, + { "redraw", 0, packagelist::kd_redraw, qa_noquit }, + { "quitcheck", 0, packagelist::kd_quit_noop, qa_quitchecksave }, + { "quitrejectsug", 0, packagelist::kd_revertdirect, qa_quitnochecksave }, + { "quitnocheck", 0, packagelist::kd_quit_noop, qa_quitnochecksave }, + { "abortnocheck", 0, packagelist::kd_revert_abort, qa_quitnochecksave }, + { "revert", 0, packagelist::kd_revert_abort, qa_noquit }, + { "revertsuggest", 0, packagelist::kd_revertsuggest, qa_noquit }, + { "revertdirect", 0, packagelist::kd_revertdirect, qa_noquit }, + { 0, 0, qa_noquit } }; #define C(x) ((x)-'a'+1) const keybindings::orgbinding packagelist_korgbindings[]= { - { 'j', "down" }, // vi style - { 'n', "down" }, - { KEY_DOWN, "down" }, - { 'k', "up" }, // vi style - { 'p', "up" }, - { KEY_UP, "up" }, - - { 'N', "scrollon" }, - { KEY_NPAGE, "scrollon" }, - { ' ', "scrollon" }, - { 'P', "scrollback" }, - { KEY_PPAGE, "scrollback" }, - { KEY_BACKSPACE, "scrollback" }, - { 0177, "scrollback" }, // ASCII DEL - { C('h'), "scrollback" }, - { C('n'), "scrollon1" }, - { C('p'), "scrollback1" }, - - { 't', "top" }, - { KEY_HOME, "top" }, - { 'e', "bottom" }, - { KEY_LL, "bottom" }, - { KEY_END, "bottom" }, - - { 'u', "iscrollback" }, - { 'd', "iscrollon" }, - { C('u'), "iscrollback1" }, - { C('d'), "iscrollon1" }, - - { 'B', "panback" }, - { KEY_LEFT, "panback" }, - { 'F', "panon" }, - { KEY_RIGHT, "panon" }, - { C('b'), "panback1" }, - { C('f'), "panon1" }, - - { '+', "select" }, - { KEY_IC, "select" }, - { '-', "deselect" }, - { KEY_DC, "deselect" }, - { '_', "purge" }, - { 'H', "hold" }, - { 'G', "unhold" }, - - { '?', "help" }, - { KEY_HELP, "help" }, - { KEY_F(1), "help" }, - { 'i', "info" }, - { 'o', "swaporder" }, - { 'v', "verbose" }, - { C('l'), "redraw" }, - { '/', "search" }, - { '\\', "searchagain" }, - - { KEY_ENTER, "quitcheck" }, - { '\r', "quitcheck" }, - { 'Q', "quitnocheck" }, - { 27, "abortnocheck" }, // esc - { 'x', "abortnocheck" }, - { 'X', "abortnocheck" }, - { 'R', "revert" }, - { 'U', "revertsuggest" }, - { 'D', "revertdirect" }, - - { -1, 0 } + { 'j', "down" }, // vi style + { 'n', "down" }, + { KEY_DOWN, "down" }, + { 'k', "up" }, // vi style + { 'p', "up" }, + { KEY_UP, "up" }, + + { 'N', "scrollon" }, + { KEY_NPAGE, "scrollon" }, + { ' ', "scrollon" }, + { 'P', "scrollback" }, + { KEY_PPAGE, "scrollback" }, + { KEY_BACKSPACE, "scrollback" }, + { 0177, "scrollback" }, // ASCII DEL + { C('h'), "scrollback" }, + { C('n'), "scrollon1" }, + { C('p'), "scrollback1" }, + + { 't', "top" }, + { KEY_HOME, "top" }, + { 'e', "bottom" }, + { KEY_LL, "bottom" }, + { KEY_END, "bottom" }, + + { 'u', "iscrollback" }, + { 'd', "iscrollon" }, + { C('u'), "iscrollback1" }, + { C('d'), "iscrollon1" }, + + { 'B', "panback" }, + { KEY_LEFT, "panback" }, + { 'F', "panon" }, + { KEY_RIGHT, "panon" }, + { C('b'), "panback1" }, + { C('f'), "panon1" }, + + { '+', "select" }, + { KEY_IC, "select" }, + { '-', "deselect" }, + { KEY_DC, "deselect" }, + { '_', "purge" }, + { 'H', "hold" }, + { '=', "unhold" }, + { 'G', "unhold" }, + + { '?', "help" }, + { KEY_HELP, "help" }, + { KEY_F(1), "help" }, + { 'i', "info" }, + { 'o', "swaporder" }, + { 'O', "swapstatorder" }, + { 'v', "verbose" }, + { 'V', "versiondisplay" }, + { C('l'), "redraw" }, + { '/', "search" }, + { '\\', "searchagain" }, + + { KEY_ENTER, "quitcheck" }, + { '\r', "quitcheck" }, + { 'Q', "quitnocheck" }, + { 27, "abortnocheck" }, // esc + { 'x', "abortnocheck" }, + { 'X', "abortnocheck" }, + { 'R', "revert" }, + { 'U', "revertsuggest" }, + { 'D', "revertdirect" }, + + { -1, 0 } }; diff --git a/dselect/pkglist.cc b/dselect/pkglist.cc index f995e96c..f5aaace2 100644 --- a/dselect/pkglist.cc +++ b/dselect/pkglist.cc @@ -35,6 +35,19 @@ extern "C" { int packagelist::compareentries(struct perpackagestate *a, struct perpackagestate *b) { + switch (statsortorder) { + case sso_avail: + if (a->ssavail != b->ssavail) return a->ssavail - b->ssavail; + break; + case sso_state: + if (a->ssstate != b->ssstate) return a->ssstate - b->ssstate; + break; + case sso_unsorted: + break; + default: + internerr("unknown statsortorder in compareentries"); + } + const char *asection= a->pkg->section; if (!asection && a->pkg->name) asection= ""; const char *bsection= b->pkg->section; @@ -87,7 +100,9 @@ void packagelist::discardheadings() { headings= 0; } -void packagelist::addheading(pkginfo::pkgpriority priority, +void packagelist::addheading(enum ssavailval ssavail, + enum ssstateval ssstate, + pkginfo::pkgpriority priority, const char *otherpriority, const char *section) { assert(nitems <= nallocated); @@ -99,8 +114,8 @@ void packagelist::addheading(pkginfo::pkgpriority priority, table= newtable; } - if (debug) fprintf(debug,"packagelist[%p]::addheading(%d,%s,%s)\n", - this,priority, + if (debug) fprintf(debug,"packagelist[%p]::addheading(%d,%d,%d,%s,%s)\n", + this,ssavail,ssstate,priority, otherpriority ? otherpriority : "", section ? section : ""); @@ -114,6 +129,9 @@ void packagelist::addheading(pkginfo::pkgpriority priority, newstate->pkg= newhead; newstate->uprec= headings; headings= newstate; + newstate->ssavail= ssavail; + newstate->ssstate= ssstate; + newhead->clientdata= newstate; table[nitems++]= newstate; } @@ -132,20 +150,111 @@ void packagelist::sortinplace() { qsort(table,nitems,sizeof(struct pkginfoperfile*),qsort_compareentries); } +void packagelist::ensurestatsortinfo() { + const struct versionrevision *veri; + const struct versionrevision *vera; + int index; + + if (debug) fprintf(debug,"packagelist[%p]::ensurestatsortinfos() " + "sortorder=%d nitems=%d\n",this,statsortorder,nitems); + + switch (statsortorder) { + case sso_unsorted: + if (debug) fprintf(debug,"packagelist[%p]::ensurestatsortinfos() unsorted\n",this); + return; + case sso_avail: + if (debug) fprintf(debug,"packagelist[%p]::ensurestatsortinfos() calcssadone=%d\n", + this,calcssadone); + if (calcssadone) return; + for (index=0; index < nitems; index++) { + if (debug) + fprintf(debug,"packagelist[%p]::ensurestatsortinfos() i=%d pkg=%s\n", + this,index,table[index]->pkg->name); + switch (table[index]->pkg->status) { + case pkginfo::stat_unpacked: + case pkginfo::stat_halfconfigured: + case pkginfo::stat_halfinstalled: + table[index]->ssavail= ssa_broken; + break; + case pkginfo::stat_notinstalled: + case pkginfo::stat_configfiles: + table[index]->ssavail= + table[index]->original == pkginfo::want_unknown + ? ssa_notinst_unseen : ssa_notinst_seen; + break; + case pkginfo::stat_installed: + veri= &table[index]->pkg->installed.version; + vera= &table[index]->pkg->available.version; + if (!informativeversion(vera)) { + table[index]->ssavail= ssa_installed_gone; + } else if (versioncompare(vera,veri) > 0) { + table[index]->ssavail= ssa_installed_newer; + } else { + table[index]->ssavail= ssa_installed_sameold; + } + break; + default: + internerr("unknown stat in ensurestatsortinfo sso_avail"); + } + if (debug) + fprintf(debug,"packagelist[%p]::ensurestatsortinfos() i=%d ssavail=%d\n", + this,index,table[index]->ssavail); + + } + calcssadone= 1; + break; + case sso_state: + if (debug) fprintf(debug,"packagelist[%p]::ensurestatsortinfos() calcsssdone=%d\n", + this,calcsssdone); + if (calcsssdone) return; + for (index=0; index < nitems; index++) { + if (debug) + fprintf(debug,"packagelist[%p]::ensurestatsortinfos() i=%d pkg=%s\n", + this,index,table[index]->pkg->name); + switch (table[index]->pkg->status) { + case pkginfo::stat_unpacked: + case pkginfo::stat_halfconfigured: + case pkginfo::stat_halfinstalled: + table[index]->ssstate= sss_broken; + break; + case pkginfo::stat_notinstalled: + table[index]->ssstate= sss_notinstalled; + break; + case pkginfo::stat_configfiles: + table[index]->ssstate= sss_configfiles; + break; + case pkginfo::stat_installed: + table[index]->ssstate= sss_installed; + break; + default: + internerr("unknown stat in ensurestatsortinfo sso_state"); + } + if (debug) + fprintf(debug,"packagelist[%p]::ensurestatsortinfos() i=%d ssstate=%d\n", + this,index,table[index]->ssstate); + + } + calcsssdone= 1; + break; + default: + internerr("unknown statsortorder in ensurestatsortinfo"); + } +} + void packagelist::sortmakeheads() { discardheadings(); + ensurestatsortinfo(); sortinplace(); assert(nitems); - if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads() sortorder=%d\n", - this,sortorder); + if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads() " + "sortorder=%d statsortorder=%d\n",this,sortorder,statsortorder); int nrealitems= nitems; - addheading(pkginfo::pri_unset,0,0); + addheading(ssa_none,sss_none,pkginfo::pri_unset,0,0); - if (sortorder == so_alpha) { sortinplace(); return; } - - assert(sortorder == so_section || sortorder == so_priority); + assert(sortorder != so_unsorted); + if (sortorder == so_alpha && statsortorder == sso_unsorted) { sortinplace(); return; } // Important: do not save pointers into table in this function, because // addheading may need to reallocate table to make it larger ! @@ -157,6 +266,24 @@ void packagelist::sortmakeheads() { for (a=0; apkg; assert(thispkg->name); + int ssdiff= 0; + ssavailval ssavail= ssa_none; + ssstateval ssstate= sss_none; + switch (statsortorder) { + case sso_avail: + ssavail= thispkg->clientdata->ssavail; + ssdiff= (!lastpkg || ssavail != lastpkg->clientdata->ssavail); + break; + case sso_state: + ssstate= thispkg->clientdata->ssstate; + ssdiff= (!lastpkg || ssstate != lastpkg->clientdata->ssstate); + break; + case sso_unsorted: + break; + default: + internerr("unknown statsortorder in sortmakeheads"); + } + int prioritydiff= (!lastpkg || thispkg->priority != lastpkg->priority || (thispkg->priority == pkginfo::pri_other && @@ -166,20 +293,35 @@ void packagelist::sortmakeheads() { lastpkg->section ? lastpkg->section : "")); if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads()" - " pkg=%s priority=%d otherpriority=%s %s section=%s %s\n", - this, thispkg->name, thispkg->priority, + " pkg=%s state=%d avail=%d %s priority=%d" + " otherpriority=%s %s section=%s %s\n", + this, thispkg->name, + thispkg->clientdata->ssavail, + thispkg->clientdata->ssstate, + ssdiff ? "*diff" : "same", + thispkg->priority, thispkg->otherpriority ? thispkg->otherpriority : "", prioritydiff ? "*diff*" : "same", thispkg->section ? thispkg->section : "", sectiondiff ? "*diff*" : "same"); + if (ssdiff) + addheading(ssavail,ssstate, + pkginfo::pri_unset,0, 0); + if (sortorder == so_section && sectiondiff) - addheading(pkginfo::pri_unset,0, thispkg->section ? thispkg->section : ""); + addheading(ssavail,ssstate, + pkginfo::pri_unset,0, thispkg->section ? thispkg->section : ""); + if (sortorder == so_priority && prioritydiff) - addheading(thispkg->priority,thispkg->otherpriority, 0); - if (prioritydiff || sectiondiff) - addheading(thispkg->priority,thispkg->otherpriority, + addheading(ssavail,ssstate, + thispkg->priority,thispkg->otherpriority, 0); + + if (sortorder != so_alpha && (prioritydiff || sectiondiff)) + addheading(ssavail,ssstate, + thispkg->priority,thispkg->otherpriority, thispkg->section ? thispkg->section : ""); + lastpkg= thispkg; } @@ -213,6 +355,7 @@ void packagelist::initialsetup() { currentinfo= 0; headings= 0; verbose= 0; + calcssadone= calcsssdone= 0; } void packagelist::finalsetup() { @@ -260,6 +403,8 @@ packagelist::packagelist(keybindings *kb) : baselist(kb) { if (!nitems) ohshit("There are no packages to select."); recursive= 0; sortorder= so_priority; + statsortorder= sso_avail; + versiondisplayopt= vdo_both; sortmakeheads(); finalsetup(); } @@ -276,6 +421,8 @@ packagelist::packagelist(keybindings *kb, pkginfo **pkgltab) : baselist(kb) { } sortorder= so_unsorted; + statsortorder= sso_unsorted; + versiondisplayopt= vdo_none; finalsetup(); } diff --git a/dselect/pkglist.h b/dselect/pkglist.h index a1d045b6..34519d2d 100644 --- a/dselect/pkglist.h +++ b/dselect/pkglist.h @@ -39,6 +39,24 @@ enum selpriority { // high }; +enum ssavailval { // Availability sorting order, first to last: + ssa_broken, // Brokenly-installed and nothing available + ssa_notinst_unseen, // Entirely new packages (available but not deselected yet) + ssa_installed_newer, // Installed, newer version available + ssa_installed_gone, // Installed but no longer available + ssa_installed_sameold, // Same or older version available as installed + ssa_notinst_seen, // Available but not installed + ssa_none=-1 +}; + +enum ssstateval { // State sorting order, first to last: + sss_broken, // In some way brokenly installed + sss_installed, // Installed + sss_configfiles, // Config files only + sss_notinstalled, // Not installed + sss_none=-1 +}; + struct perpackagestate { struct pkginfo *pkg; /* The `heading' entries in the list, for `all packages of type foo', @@ -55,6 +73,8 @@ struct perpackagestate { selpriority spriority; // monotonically increases (used by sublists) showpriority dpriority; // monotonically increases (used by sublists) struct perpackagestate *uprec; // 0 if this is not part of a recursive list + ssavailval ssavail; + ssstateval ssstate; varbuf relations; void free(int recursive); @@ -62,8 +82,9 @@ struct perpackagestate { class packagelist : public baselist { int status_width, gap_width, section_width, priority_width; - int package_width, description_width; - int section_column, priority_column, package_column, description_column; + int package_width, versioninstalled_width, versionavailable_width, description_width; + int section_column, priority_column, versioninstalled_column; + int versionavailable_column, package_column, description_column; // Only used when `verbose' is set int status_hold_width, status_status_width, status_want_width; @@ -75,6 +96,9 @@ class packagelist : public baselist { // Misc. int recursive, nallocated, verbose; enum { so_unsorted, so_section, so_priority, so_alpha } sortorder; + enum { sso_unsorted, sso_avail, sso_state } statsortorder; + enum { vdo_none, vdo_available, vdo_both } versiondisplayopt; + int calcssadone, calcsssdone; struct perpackagestate *headings; // Information displays @@ -116,15 +140,21 @@ class packagelist : public baselist { void redraw1package(int index, int selected); int compareentries(struct perpackagestate *a, struct perpackagestate *b); friend int qsort_compareentries(const void *a, const void *b); + pkginfo::pkgwant reallywant(pkginfo::pkgwant, struct perpackagestate*); + int describemany(char buf[], const char *prioritystring, const char *section, + const struct perpackagestate *pps); void sortmakeheads(); + void resortredisplay(); void movecursorafter(int ncursor); void initialsetup(); void finalsetup(); + void ensurestatsortinfo(); // To do with building the list, with heading lines in it void discardheadings(); - void addheading(pkginfo::pkgpriority,const char*, const char *section); + void addheading(enum ssavailval, enum ssstateval, + pkginfo::pkgpriority, const char*, const char *section); void sortinplace(); void affectedrange(int *startp, int *endp); void setwant(pkginfo::pkgwant nw); @@ -140,6 +170,7 @@ class packagelist : public baselist { void kd_morespecific(); void kd_lessspecific(); void kd_swaporder(); + void kd_swapstatorder(); void kd_select(); void kd_deselect(); void kd_purge(); @@ -147,6 +178,7 @@ class packagelist : public baselist { void kd_unhold(); void kd_info(); void kd_verbose(); + void kd_versiondisplay(); packagelist(keybindings *kb); // nonrecursive packagelist(keybindings *kb, pkginfo **pkgltab); // recursive @@ -164,15 +196,18 @@ class packagelist : public baselist { }; void repeatedlydisplay(packagelist *sub, showpriority, packagelist *unredisplay =0); +int would_like_to_install(pkginfo::pkgwant, pkginfo *pkg); extern const char *const wantstrings[]; -extern const char *const holdstrings[]; +extern const char *const eflagstrings[]; extern const char *const statusstrings[]; extern const char *const prioritystrings[]; extern const char *const priorityabbrevs[]; extern const char *const relatestrings[]; +extern const char *const ssastrings[], *const ssaabbrevs[]; +extern const char *const sssstrings[], *const sssabbrevs[]; extern const char statuschars[]; -extern const char holdchars[]; +extern const char eflagchars[]; extern const char wantchars[]; const struct pkginfoperfile *i2info(struct pkginfo *pkg); diff --git a/dselect/pkgsublist.cc b/dselect/pkgsublist.cc index ccaf2e93..75216f4e 100644 --- a/dselect/pkgsublist.cc +++ b/dselect/pkgsublist.cc @@ -58,7 +58,7 @@ void packagelist::add(pkginfo *pkg, pkginfo::pkgwant nw) { add(pkg); if (!pkg->clientdata) return; pkg->clientdata->direct= nw; selpriority np; - np= (nw == pkginfo::want_install) ? sp_selecting : sp_deselecting; + np= would_like_to_install(nw,pkg) ? sp_selecting : sp_deselecting; if (pkg->clientdata->spriority > np) return; if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s, %s) setting\n", this,pkg->name,wantstrings[nw]); @@ -122,7 +122,7 @@ int packagelist::add(dependency *depends, showpriority displayimportance) { possi=possi->next, comma=(possi && possi->next ? ", " : " or ")) { info(comma); info(possi->ed->name); - if (possi->version && *possi->version) { + if (possi->verrel != deppossi::dvr_none) { switch (possi->verrel) { case deppossi::dvr_earlierequal: info(" (<= "); break; case deppossi::dvr_laterequal: info(" (>= "); break; @@ -131,11 +131,7 @@ int packagelist::add(dependency *depends, showpriority displayimportance) { case deppossi::dvr_exact: info(" (= "); break; default: internerr("unknown verrel"); } - info(possi->version); - if (possi->revision && *possi->revision) { - info('-'); - info(possi->revision); - } + info(versiondescribe(&possi->version,vdew_never)); info(")"); } } @@ -143,7 +139,7 @@ int packagelist::add(dependency *depends, showpriority displayimportance) { add(depends->up,info.string(),displayimportance); for (possi=depends->list; possi; possi=possi->next) { add(possi->ed,info.string(),displayimportance); - if (depends->type != dep_provides && (!possi->version || !*possi->version)) { + if (possi->verrel == deppossi::dvr_none && depends->type != dep_provides) { // providers aren't relevant if a version was specified, or // if we're looking at a provider relationship already deppossi *provider; diff --git a/dselect/pkgtop.cc b/dselect/pkgtop.cc index 845b5dd7..efb68586 100644 --- a/dselect/pkgtop.cc +++ b/dselect/pkgtop.cc @@ -45,30 +45,57 @@ const char *pkgprioritystring(const struct pkginfo *pkg) { } } -static int describemany(char buf[], const char *prioritystring, const char *section) { +int packagelist::describemany(char buf[], const char *prioritystring, + const char *section, + const struct perpackagestate *pps) { + const char *ssostring, *ssoabbrev; + int statindent; + + statindent= 0; + ssostring= 0; + ssoabbrev= "All"; + switch (statsortorder) { + case sso_avail: + if (pps->ssavail == -1) break; + ssostring= ssastrings[pps->ssavail]; + ssoabbrev= ssaabbrevs[pps->ssavail]; + statindent++; + break; + case sso_state: + if (pps->ssstate == -1) break; + ssostring= sssstrings[pps->ssstate]; + ssoabbrev= sssabbrevs[pps->ssstate]; + statindent++; + break; + case sso_unsorted: + break; + default: + internerr("unknown statsortrder in describemany all"); + } + if (!prioritystring) { if (!section) { - strcpy(buf, "All packages"); - return 0; + strcpy(buf, ssostring ? ssostring : "All packages"); + return statindent; } else { if (!*section) { - strcpy(buf, "All packages without a section"); + sprintf(buf,"%s packages without a section",ssoabbrev); } else { - sprintf(buf, "All packages in section %s", section); + sprintf(buf,"%s packages in section %s",ssoabbrev,section); } - return 1; + return statindent+1; } } else { if (!section) { - sprintf(buf, "All %s packages", prioritystring); - return 1; + sprintf(buf,"%s %s packages",ssoabbrev,prioritystring); + return statindent+1; } else { if (!*section) { - sprintf(buf, "All %s packages without a section", prioritystring); + sprintf(buf,"%s %s packages without a section",ssoabbrev,prioritystring); } else { - sprintf(buf, "All %s packages in section %s", prioritystring, section); + sprintf(buf,"%s %s packages in section %s",ssoabbrev,prioritystring,section); } - return 2; + return statindent+2; } } } @@ -79,7 +106,7 @@ void packagelist::redrawthisstate() { const char *section= table[cursorline]->pkg->section; const char *priority= pkgprioritystring(table[cursorline]->pkg); - char *buf= new char[220+ + char *buf= new char[500+ greaterint((table[cursorline]->pkg->name ? strlen(table[cursorline]->pkg->name) : 0), (section ? strlen(section) : 0) + @@ -91,13 +118,13 @@ void packagelist::redrawthisstate() { package_width, table[cursorline]->pkg->name, statusstrings[table[cursorline]->pkg->status], - holdstrings[table[cursorline]->pkg->eflag][0] ? " - " : "", - holdstrings[table[cursorline]->pkg->eflag], + eflagstrings[table[cursorline]->pkg->eflag][0] ? " - " : "", + eflagstrings[table[cursorline]->pkg->eflag], wantstrings[table[cursorline]->selected], wantstrings[table[cursorline]->original], priority); } else { - describemany(buf,priority,section); + describemany(buf,priority,section,table[cursorline]->pkg->clientdata); } mvwaddnstr(thisstatepad,0,0, buf, total_width); pnoutrefresh(thisstatepad, 0,leftofscreen, thisstate_row,0, @@ -120,7 +147,7 @@ void packagelist::redraw1itemsel(int index, int selected) { mvwprintw(listpad,index,0, "%-*.*s ", status_hold_width, status_hold_width, - holdstrings[pkg->eflag]); + eflagstrings[pkg->eflag]); wprintw(listpad, "%-*.*s ", status_status_width, status_status_width, statusstrings[pkg->status]); @@ -143,7 +170,7 @@ void packagelist::redraw1itemsel(int index, int selected) { } else { - mvwaddch(listpad,index,0, holdchars[pkg->eflag]); + mvwaddch(listpad,index,0, eflagchars[pkg->eflag]); waddch(listpad, statuschars[pkg->status]); waddch(listpad, /* fixme: keep this feature? */ @@ -176,7 +203,22 @@ void packagelist::redraw1itemsel(int index, int selected) { mvwprintw(listpad,index,package_column-1, " %-*.*s ", package_width, package_width, pkg->name); - + + if (versioninstalled_width) + mvwprintw(listpad,index,versioninstalled_column, "%-*.*s ", + versioninstalled_width, versioninstalled_width, + versiondescribe(&pkg->installed.version,vdew_never)); + if (versionavailable_width) { + if (informativeversion(&pkg->available.version) && + versioncompare(&pkg->available.version,&pkg->installed.version) > 0) + wattrset(listpad, selected ? selstatesel_attr : selstate_attr); + mvwprintw(listpad,index,versionavailable_column, "%-*.*s", + versionavailable_width, versionavailable_width, + versiondescribe(&pkg->available.version,vdew_never)); + wattrset(listpad, selected ? listsel_attr : list_attr); + waddch(listpad,' '); + } + i= description_width; p= info->description ? info->description : ""; while (i>0 && *p && *p != '\n') { waddch(listpad,*p); i--; p++; } @@ -186,11 +228,11 @@ void packagelist::redraw1itemsel(int index, int selected) { const char *section= pkg->section; const char *priority= pkgprioritystring(pkg); - char *buf= new char[220+ + char *buf= new char[500+ (section ? strlen(section) : 0) + (priority ? strlen(priority) : 0)]; - indent= describemany(buf,priority,section); + indent= describemany(buf,priority,section,pkg->clientdata); mvwaddstr(listpad,index,0, " "); i= total_width-6; @@ -243,6 +285,14 @@ void packagelist::redrawcolheads() { mvwaddnstr(colheadspad,0,section_column, "Section", section_width); mvwaddnstr(colheadspad,0,priority_column, "Priority", priority_width); mvwaddnstr(colheadspad,0,package_column, "Package", package_width); + + if (versioninstalled_width) + mvwaddnstr(colheadspad,0,versioninstalled_column, + "Inst.ver",versioninstalled_width); + if (versionavailable_width) + mvwaddnstr(colheadspad,0,versionavailable_column, + "Avail.ver",versionavailable_width); + mvwaddnstr(colheadspad,0,description_column, "Description", description_width); } refreshcolheads(); diff --git a/include/dpkg-db.h b/include/dpkg-db.h index 202c07fc..d00f6cde 100644 --- a/include/dpkg-db.h +++ b/include/dpkg-db.h @@ -42,6 +42,11 @@ struct dependency { /* dy */ enum deptype type; }; +struct versionrevision { + unsigned long epoch; + char *version, *revision; +}; + struct deppossi { /* do */ struct dependency *up; struct pkginfo *ed; @@ -59,7 +64,7 @@ struct deppossi { /* do */ dvr_laterstrict= dvrf_builtup | dvrf_later | dvrf_strict, dvr_exact= 0400 } verrel; - char *version, *revision; + struct versionrevision version; int cyclebreak; }; @@ -85,7 +90,8 @@ struct pkginfoperfile { /* pif */ struct dependency *depends; struct deppossi *depended; int essential; /* The `essential' flag, 1=yes, 0=no (absent) */ - char *description, *maintainer, *version, *revision, *source, *architecture; + char *description, *maintainer, *source, *architecture; + struct versionrevision version; struct conffile *conffiles; struct arbitraryfield *arbs; }; @@ -96,12 +102,18 @@ struct pkginfo { /* pig */ struct pkginfo *next; char *name; enum pkgwant { - want_unknown, want_install, want_deinstall, want_purge + want_unknown, want_install, want_hold, want_deinstall, want_purge, + want_sentinel /* Not allowed except as special sentinel value + in some places */ } want; enum pkgeflag { - eflagv_ok=00, eflagv_hold=01, eflagv_reinstreq=02, eflagv_both=03, - eflagf_hold=01, eflagf_reinstreq=02 - } eflag; /* bitmask */ + eflagf_reinstreq = 01, + eflagf_obsoletehold = 02, + eflagv_ok = 0, + eflagv_reinstreq = eflagf_reinstreq, + eflagv_obsoletehold = eflagf_obsoletehold, + eflagv_obsoleteboth = eflagf_reinstreq | eflagf_obsoletehold + } eflag; /* bitmask, but obsoletehold no longer used except when reading */ enum pkgstatus { stat_notinstalled, stat_unpacked, stat_halfconfigured, stat_installed, stat_halfinstalled, stat_configfiles @@ -113,7 +125,7 @@ struct pkginfo { /* pig */ } priority; char *otherpriority; char *section; - char *configversion, *configrevision; + struct versionrevision configversion; struct filedetails *files; struct pkginfoperfile installed; struct pkginfoperfile available; @@ -150,6 +162,7 @@ extern char *statusfile, *availablefile; /* initialised by modstatdb_init */ struct pkginfo *findpackage(const char *name); void blankpackage(struct pkginfo *pp); void blankpackageperfile(struct pkginfoperfile *pifp); +void blankversion(struct versionrevision*); int informative(struct pkginfo *pkg, struct pkginfoperfile *info); int countpackages(void); void resetpackages(void); @@ -192,6 +205,15 @@ extern const struct namevalue wantinfos[]; const char *skip_slash_dotslash(const char *p); +int informativeversion(const struct versionrevision *version); + +enum versiondisplayepochwhen { vdew_never, vdew_nonambig, vdew_always }; +void varbufversion(struct varbuf*, const struct versionrevision*, + enum versiondisplayepochwhen); +const char *parseversion(struct versionrevision *rversion, const char*); +const char *versiondescribe(const struct versionrevision*, + enum versiondisplayepochwhen); + /*** from varbuf.c ***/ struct varbuf; @@ -255,12 +277,15 @@ void writedb(const char *filename, int available, int mustsync); void varbufrecord(struct varbuf*, const struct pkginfo*, const struct pkginfoperfile*); void varbufdependency(struct varbuf *vb, struct dependency *dep); +void varbufprintf(struct varbuf *v, const char *fmt, ...) PRINTFFORMAT(2,3); /* NB THE VARBUF MUST HAVE BEEN INITIALISED AND WILL NOT BE NULL-TERMINATED */ /*** from vercmp.c ***/ -int versioncompare(const char *version, const char *revision, - const char *refversion, const char *refrevision); +int versioncompare(const struct versionrevision *version, + const struct versionrevision *refversion); +int epochsdiffer(const struct versionrevision *a, + const struct versionrevision *b); /*** from nfmalloc.c ***/ diff --git a/include/dpkg.h b/include/dpkg.h index 937c535f..d00f77fe 100644 --- a/include/dpkg.h +++ b/include/dpkg.h @@ -46,7 +46,10 @@ #define REMOVECONFFEXTS "~", ".bak", "%", \ DPKGTEMPEXT, DPKGNEWEXT, DPKGOLDEXT, DPKGDISTEXT -#define DPKG_VERSION_ARCH DPKG_VERSION " (" ARCHITECTURE ")" +#ifndef ARCHBINFMT +#define ARCHBINFMT +#endif +#define DPKG_VERSION_ARCH DPKG_VERSION " (" ARCHITECTURE ARCHBINFMT ")" #define NEWCONFFILEFLAG "newconffile" #define NONEXISTENTFLAG "nonexistent" diff --git a/lib/compat.c b/lib/compat.c index 94ae4034..3c349e22 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -25,8 +25,52 @@ #include #include #include +#include +#include +#include +#include #include "config.h" +#include "dpkg.h" + +char *strcpy(char *to, const char *from) { + char *oto= to; + while ((*to++ = *from++) != 0); + return oto; +} + +#ifndef HAVE_VSNPRINTF +int vsnprintf (char *buf, size_t maxsize, const char *fmt, va_list al) { + static FILE *file= 0; + + struct stat stab; + unsigned long want, nr; + int retval; + + if (maxsize == 0) return -1; + if (!file) { + file= tmpfile(); if (!file) ohshite("unable to open tmpfile for vsnprintf"); + } else { + if (fseek(file,0,0)) ohshite("unable to rewind at start of vsnprintf"); + if (ftruncate(fileno(file),0)) ohshite("unable to truncate in vsnprintf"); + } + if (vfprintf(file,fmt,al) == EOF) ohshite("write error in vsnprintf"); + if (fflush(file)) ohshite("unable to flush in vsnprintf"); + if (fstat(fileno(file),&stab)) ohshite("unable to stat in vsnprintf"); + if (fseek(file,0,0)) ohshite("unable to rewind in vsnprintf"); + want= stab.st_size; + if (want >= maxsize) { + want= maxsize-1; retval= -1; + } else { + retval= want; + } + nr= fread(buf,1,want-1,file); + if (nr != want-1) ohshite("read error in vsnprintf truncated"); + buf[want]= 0; + + return retval; +} +#endif #ifndef HAVE_STRERROR extern const char *const sys_errlist[]; diff --git a/lib/database.c b/lib/database.c index 71250e7e..de5f903a 100644 --- a/lib/database.c +++ b/lib/database.c @@ -106,13 +106,19 @@ static int hash(const char *name) { */ } +void blankversion(struct versionrevision *version) { + version->epoch= 0; + version->version= version->revision= 0; +} + void blankpackage(struct pkginfo *pigp) { pigp->name= 0; pigp->status= stat_notinstalled; pigp->eflag= eflagv_ok; pigp->want= want_unknown; pigp->priority= pri_unknown; - pigp->section= pigp->configversion= pigp->configrevision= 0; + pigp->section= 0; + blankversion(&pigp->configversion); pigp->files= 0; pigp->installed.valid= 0; pigp->available.valid= 0; @@ -124,7 +130,8 @@ void blankpackageperfile(struct pkginfoperfile *pifp) { pifp->depends= 0; pifp->depended= 0; pifp->description= pifp->maintainer= pifp->source= 0; - pifp->architecture= pifp->version= pifp->revision= 0; + pifp->architecture= 0; + blankversion(&pifp->version); pifp->conffiles= 0; pifp->arbs= 0; pifp->valid= 1; @@ -141,6 +148,7 @@ int informative(struct pkginfo *pkg, struct pkginfoperfile *info) { ((pkg->want != want_unknown && pkg->want != want_purge) || pkg->eflag != eflagv_ok || pkg->status != stat_notinstalled || + informativeversion(&pkg->configversion) || pkg->files) : (nes(pkg->section) || @@ -152,8 +160,7 @@ int informative(struct pkginfo *pkg, struct pkginfoperfile *info) { nes(info->maintainer) || nes(info->source) || nes(info->architecture) || - nes(info->version) || - nes(info->revision) || + informativeversion(&info->version) || info->conffiles || info->arbs) return 1; return 0; diff --git a/lib/dump.c b/lib/dump.c index fb9aa765..5309bc7c 100644 --- a/lib/dump.c +++ b/lib/dump.c @@ -44,31 +44,21 @@ void w_name(struct varbuf *vb, void w_version(struct varbuf *vb, const struct pkginfo *pigp, const struct pkginfoperfile *pifp, const struct fieldinfo *fip) { - /* Revision information is printed in version field too. */ - if ((!pifp->version || !*pifp->version) && - (!pifp->revision || !*pifp->revision)) return; + /* Epoch and revision information is printed in version field too. */ + if (!informativeversion(&pifp->version)) return; varbufaddstr(vb,"Version: "); - varbufaddstr(vb,pifp->version ? pifp->version : ""); - if (pifp->revision && *pifp->revision) { - varbufaddc(vb,'-'); - varbufaddstr(vb,pifp->revision); - } + varbufversion(vb,&pifp->version,vdew_nonambig); varbufaddc(vb,'\n'); } void w_configversion(struct varbuf *vb, const struct pkginfo *pigp, const struct pkginfoperfile *pifp, const struct fieldinfo *fip) { - if ((!pigp->configversion || !*pigp->configversion) && - (!pigp->configrevision || !*pigp->configrevision)) return; if (pifp != &pigp->installed) return; + if (!informativeversion(&pigp->configversion)) return; if (pigp->status == stat_installed || pigp->status == stat_notinstalled) return; varbufaddstr(vb,"Config-Version: "); - varbufaddstr(vb,pigp->configversion ? pigp->configversion : ""); - if (pigp->configrevision && *pigp->configrevision) { - varbufaddc(vb,'-'); - varbufaddstr(vb,pigp->configrevision); - } + varbufversion(vb,&pigp->configversion,vdew_nonambig); varbufaddc(vb,'\n'); } @@ -140,7 +130,7 @@ void w_status(struct varbuf *vb, const struct fieldinfo *fip) { if (pifp != &pigp->installed) return; assert(pigp->want <= want_purge && - pigp->eflag <= eflagv_both && + pigp->eflag <= eflagv_reinstreq && /* hold and hold-reinstreq NOT allowed */ pigp->status <= stat_configfiles); varbufaddstr(vb,"Status: "); varbufaddstr(vb,wantinfos[pigp->want].name); varbufaddc(vb,' '); @@ -167,9 +157,8 @@ void varbufdependency(struct varbuf *vb, struct dependency *dep) { case dvr_earlierstrict: varbufaddstr(vb,"<<"); break; default: internerr("unknown verrel"); } - if (!isalnum(dop->version[0])) varbufaddc(vb,' '); - varbufaddstr(vb,dop->version); - if (dop->revision) { varbufaddc(vb,'-'); varbufaddstr(vb,dop->revision); } + varbufaddc(vb,' '); + varbufversion(vb,&dop->version,vdew_nonambig); varbufaddc(vb,')'); } } diff --git a/lib/fields.c b/lib/fields.c index 9066c043..103a2275 100644 --- a/lib/fields.c +++ b/lib/fields.c @@ -158,27 +158,55 @@ void f_status(struct pkginfo *pigp, struct pkginfoperfile *pifp, warnto,warncount,pigp, value,wantinfos,&ep); pigp->eflag= convert_string(filename,lno,"second (error) word in `status' field", -1, warnto,warncount,pigp, ep,eflaginfos,&ep); + if (pigp->eflag & eflagf_obsoletehold) { + pigp->want= want_hold; + pigp->eflag &= ~eflagf_obsoletehold; + } pigp->status= convert_string(filename,lno,"third (status) word in `status' field", -1, warnto,warncount,pigp, ep,statusinfos,0); } +void f_version(struct pkginfo *pigp, struct pkginfoperfile *pifp, + enum parsedbflags flags, + const char *filename, int lno, FILE *warnto, int *warncount, + const char *value, const struct fieldinfo *fip) { + const char *emsg; + + emsg= parseversion(&pifp->version,value); + if (emsg) parseerr(0,filename,lno, warnto,warncount,pigp,0, "error " + "in Version string `%.250s': %.250s",value,emsg); +} + +void f_revision(struct pkginfo *pigp, struct pkginfoperfile *pifp, + enum parsedbflags flags, + const char *filename, int lno, FILE *warnto, int *warncount, + const char *value, const struct fieldinfo *fip) { + char *newversion; + + parseerr(0,filename,lno, warnto,warncount,pigp,1, + "obsolete `Revision' or `Package-Revision' field used"); + if (!*value) return; + if (pifp->version.revision && *pifp->version.revision) { + newversion= nfmalloc(strlen(pifp->version.version)+strlen(pifp->version.revision)+2); + sprintf(newversion,"%s-%s",pifp->version.version,pifp->version.revision); + } + pifp->version.revision= nfstrsave(value); +} + void f_configversion(struct pkginfo *pigp, struct pkginfoperfile *pifp, enum parsedbflags flags, const char *filename, int lno, FILE *warnto, int *warncount, const char *value, const struct fieldinfo *fip) { - char *mycopy, *hyphen; - + const char *emsg; + if (flags & pdb_rejectstatus) parseerr(0,filename,lno, warnto,warncount,pigp,0, "value for `config-version' field not allowed in this context"); if (flags & pdb_recordavailable) return; - mycopy= nfstrsave(value); - hyphen= strrchr(mycopy,'-'); - if (hyphen) *hyphen++= 0; - - pigp->configversion= mycopy; - pigp->configrevision= hyphen ? hyphen : nfstrsave(""); + emsg= parseversion(&pigp->configversion,value); + if (emsg) parseerr(0,filename,lno, warnto,warncount,pigp,0, "error " + "in Config-Version string `%.250s': %.250s",value,emsg); } void f_conffiles(struct pkginfo *pigp, struct pkginfoperfile *pifp, @@ -223,7 +251,7 @@ void f_dependency(struct pkginfo *pigp, struct pkginfoperfile *pifp, enum parsedbflags flags, const char *filename, int lno, FILE *warnto, int *warncount, const char *value, const struct fieldinfo *fip) { - char *q, c1, c2; + char c1, c2; const char *p, *emsg; struct varbuf depname, version; struct dependency *dyp, **ldypp; @@ -253,7 +281,7 @@ void f_dependency(struct pkginfo *pigp, struct pkginfoperfile *pifp, emsg= illegal_packagename(depname.buf,0); if (emsg) parseerr(0,filename,lno, warnto,warncount,pigp,0, "`%s' field," " invalid package name `%.255s': %s", - fip->name, depname.buf, emsg); + fip->name,depname.buf,emsg); dop= nfmalloc(sizeof(struct deppossi)); dop->up= dyp; dop->ed= findpackage(depname.buf); @@ -315,24 +343,20 @@ void f_dependency(struct pkginfo *pigp, struct pkginfoperfile *pifp, p++; } if (*p == '(') parseerr(0,filename,lno, warnto,warncount,pigp,0, - "`%s' field, reference to `%.255s'" - " version contains (", fip->name, depname.buf); + "`%s' field, reference to `%.255s': " + "version contains `('",fip->name,depname.buf); else if (*p == 0) parseerr(0,filename,lno, warnto,warncount,pigp,0, - "`%s' field, reference to `%.255s'" - "version unterminated", fip->name, depname.buf); + "`%s' field, reference to `%.255s': " + "version unterminated",fip->name,depname.buf); varbufaddc(&version,0); - q= strrchr(version.buf,'-'); - if (q) { - *q++= 0; - dop->revision= nfstrsave(q); - } else { - dop->revision= 0; - } - dop->version= nfstrsave(version.buf); + emsg= parseversion(&dop->version,version.buf); + if (emsg) parseerr(0,filename,lno, warnto,warncount,pigp,0, + "`%s' field, reference to `%.255s': " + "error in version: %.255s",fip->name,depname.buf,emsg); p++; while (isspace(*p)) p++; } else { dop->verrel= dvr_none; - dop->revision= dop->version= 0; + blankversion(&dop->version); } if (!*p || *p == ',') break; if (*p != '|') diff --git a/lib/parse.c b/lib/parse.c index 15be97b5..0d367f46 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -31,32 +31,32 @@ const struct fieldinfo fieldinfos[]= { /* NB: capitalisation of these strings is important. */ - { "Package", f_name, w_name }, - { "Essential", f_boolean, w_booleandefno, PKGIFPOFF(essential) }, - { "Status", f_status, w_status }, - { "Priority", f_priority, w_priority }, - { "Section", f_section, w_section }, - { "Maintainer", f_charfield, w_charfield, PKGIFPOFF(maintainer) }, - { "Architecture", f_charfield, w_charfield, PKGIFPOFF(architecture) }, - { "Source", f_charfield, w_charfield, PKGIFPOFF(source) }, - { "Version", f_charfield, w_version, PKGIFPOFF(version) }, - { "Revision", f_charfield, w_null, PKGIFPOFF(revision) }, - { "Config-Version", f_configversion, w_configversion }, - { "Replaces", f_dependency, w_dependency, dep_replaces }, - { "Provides", f_dependency, w_dependency, dep_provides }, - { "Depends", f_dependency, w_dependency, dep_depends }, - { "Pre-Depends", f_dependency, w_dependency, dep_predepends }, - { "Recommends", f_dependency, w_dependency, dep_recommends }, - { "Suggests", f_dependency, w_dependency, dep_suggests }, - { "Conflicts", f_dependency, w_dependency, dep_conflicts }, - { "Conffiles", f_conffiles, w_conffiles }, - { "Filename", f_filecharf, w_filecharf, FILEFOFF(name) }, - { "Size", f_filecharf, w_filecharf, FILEFOFF(size) }, - { "MD5sum", f_filecharf, w_filecharf, FILEFOFF(md5sum) }, - { "MSDOS-Filename", f_filecharf, w_filecharf, FILEFOFF(msdosname) }, - { "Description", f_charfield, w_charfield, PKGIFPOFF(description) }, + { "Package", f_name, w_name }, + { "Essential", f_boolean, w_booleandefno, PKGIFPOFF(essential) }, + { "Status", f_status, w_status }, + { "Priority", f_priority, w_priority }, + { "Section", f_section, w_section }, + { "Maintainer", f_charfield, w_charfield, PKGIFPOFF(maintainer) }, + { "Architecture", f_charfield, w_charfield, PKGIFPOFF(architecture) }, + { "Source", f_charfield, w_charfield, PKGIFPOFF(source) }, + { "Version", f_version, w_version }, + { "Revision", f_revision, w_null }, + { "Config-Version", f_configversion, w_configversion }, + { "Replaces", f_dependency, w_dependency, dep_replaces }, + { "Provides", f_dependency, w_dependency, dep_provides }, + { "Depends", f_dependency, w_dependency, dep_depends }, + { "Pre-Depends", f_dependency, w_dependency, dep_predepends }, + { "Recommends", f_dependency, w_dependency, dep_recommends }, + { "Suggests", f_dependency, w_dependency, dep_suggests }, + { "Conflicts", f_dependency, w_dependency, dep_conflicts }, + { "Conffiles", f_conffiles, w_conffiles }, + { "Filename", f_filecharf, w_filecharf, FILEFOFF(name) }, + { "Size", f_filecharf, w_filecharf, FILEFOFF(size) }, + { "MD5sum", f_filecharf, w_filecharf, FILEFOFF(md5sum) }, + { "MSDOS-Filename", f_filecharf, w_filecharf, FILEFOFF(msdosname) }, + { "Description", f_charfield, w_charfield, PKGIFPOFF(description) }, /* Note that aliases are added to the nicknames table in parsehelp.c. */ - { 0 /* sentinel - tells code that list is ended */ } + { 0 /* sentinel - tells code that list is ended */ } }; #define NFIELDS (sizeof(fieldinfos)/sizeof(struct fieldinfo)) const int nfields= NFIELDS; @@ -81,7 +81,6 @@ int parsedb(const char *filename, enum parsedbflags flags, const struct fieldinfo *fip; const struct nickname *nick; const char *fieldname; - char *hyphen; int *ip, i, c; if (warncount) *warncount= 0; @@ -199,7 +198,7 @@ int parsedb(const char *filename, enum parsedbflags flags, parsemustfield(file,filename,lno, warnto,warncount,&newpig,1, &newpifp->maintainer, "maintainer"); parsemustfield(file,filename,lno, warnto,warncount,&newpig,1, - &newpifp->version, "version"); + &newpifp->version.version, "version"); } if (flags & pdb_recordavailable) parsemustfield(file,filename,lno, warnto,warncount,&newpig,1, @@ -207,20 +206,6 @@ int parsedb(const char *filename, enum parsedbflags flags, else if (newpifp->architecture && *newpifp->architecture) newpifp->architecture= 0; - /* Break out the revision */ - if (newpifp->revision) { - parseerr(file,filename,lno, warnto,warncount,&newpig,1, - "obsolete `Revision' or `Package-Revision' field used"); - } else if (newpifp->version) { - hyphen= strrchr(newpifp->version,'-'); - if (hyphen) { - *hyphen++= 0; - newpifp->revision= hyphen; - } else { - newpifp->revision= nfstrsave(""); - } - } - /* Check the Config-Version information: * If there is a Config-Version it is definitely to be used, but * there shouldn't be one if the package is `installed' (in which case @@ -228,15 +213,12 @@ int parsedb(const char *filename, enum parsedbflags flags, * `not-installed' (in which case there is no Config-Version). */ if (!(flags & pdb_recordavailable)) { - if (newpig.configversion) { + if (newpig.configversion.version) { if (newpig.status == stat_installed || newpig.status == stat_notinstalled) parseerr(file,filename,lno, warnto,warncount,&newpig,0, "Configured-Version for package with inappropriate Status"); } else { - if (newpig.status == stat_installed) { - newpig.configversion= newpifp->version; - newpig.configrevision= newpifp->revision; - } + if (newpig.status == stat_installed) newpig.configversion= newpifp->version; } } @@ -245,8 +227,7 @@ int parsedb(const char *filename, enum parsedbflags flags, if (!pifp->valid) blankpackageperfile(pifp); if (!(flags & pdb_preferversion) || - versioncompare(newpifp->version,newpifp->revision, - pifp->version,pifp->revision) >= 0) { + versioncompare(&newpifp->version,&pifp->version) >= 0) { /* If we're ignoring older versions compare version numbers * and only process this entry if it's a higher version. */ @@ -281,7 +262,6 @@ int parsedb(const char *filename, enum parsedbflags flags, pigp->eflag= newpig.eflag; pigp->status= newpig.status; pigp->configversion= newpig.configversion; - pigp->configrevision= newpig.configrevision; pigp->files= 0; } else { pigp->files= newpig.files; diff --git a/lib/parsedump.h b/lib/parsedump.h index ced6ec78..c964ede6 100644 --- a/lib/parsedump.h +++ b/lib/parsedump.h @@ -46,12 +46,14 @@ typedef void freadfunction(struct pkginfo *pigp, struct pkginfoperfile *pifp, const char *filename, int lno, FILE *warnto, int *warncount, const char *value, const struct fieldinfo *fip); freadfunction f_name, f_charfield, f_priority, f_section, f_status, f_filecharf; -freadfunction f_boolean, f_dependency, f_conffiles, f_configversion; +freadfunction f_boolean, f_dependency, f_conffiles, f_version, f_revision; +freadfunction f_configversion; typedef void fwritefunction(struct varbuf*, const struct pkginfo*, const struct pkginfoperfile*, const struct fieldinfo*); fwritefunction w_name, w_charfield, w_priority, w_section, w_status, w_configversion; -fwritefunction w_version, w_null, w_booleandefno, w_dependency, w_conffiles, w_filecharf; +fwritefunction w_version, w_null, w_booleandefno, w_dependency, w_conffiles; +fwritefunction w_filecharf; struct fieldinfo { const char *name; diff --git a/lib/parsehelp.c b/lib/parsehelp.c index 8d9c8595..c6b81f7d 100644 --- a/lib/parsehelp.c +++ b/lib/parsehelp.c @@ -88,23 +88,24 @@ const struct namevalue statusinfos[]= { /* Note ! These must be in order ! */ }; const struct namevalue eflaginfos[]= { /* Note ! These must be in order ! */ - { "ok", eflagv_ok }, - { "hold", eflagv_hold }, - { "reinstreq", eflagv_reinstreq }, - { "hold-reinstreq", eflagv_both }, - { 0 } + { "ok", eflagv_ok }, + { "reinstreq", eflagv_reinstreq }, + { "hold", eflagv_obsoletehold }, + { "hold-reinstreq", eflagv_obsoleteboth }, + { 0 } }; const struct namevalue wantinfos[]= { /* Note ! These must be in order ! */ { "unknown", want_unknown }, { "install", want_install }, + { "hold", want_hold }, { "deinstall", want_deinstall }, { "purge", want_purge }, { 0 } }; const char *illegal_packagename(const char *p, const char **ep) { - static const char alsoallowed[]= "-_+.@:=%"; + static const char alsoallowed[]= "-+._"; /* _ is deprecated */ static char buf[150]; int c; @@ -134,6 +135,76 @@ const struct nickname nicknames[]= { { 0 } }; +int informativeversion(const struct versionrevision *version) { + return (version->epoch || + (version->version && *version->version) || + (version->revision && *version->revision)); +} + +void varbufversion(struct varbuf *vb, + const struct versionrevision *version, + enum versiondisplayepochwhen vdew) { + switch (vdew) { + case vdew_never: + break; + case vdew_nonambig: + if (!version->epoch && + (!version->version || !strchr(version->version,':')) && + (!version->revision || !strchr(version->revision,':'))) break; + case vdew_always: /* FALL THROUGH */ + varbufprintf(vb,"%lu:",version->epoch); + break; + default: + internerr("bad versiondisplayepochwhen in varbufversion"); + } + if (version->version) varbufaddstr(vb,version->version); + if (version->revision && *version->revision) { + varbufaddc(vb,'-'); + varbufaddstr(vb,version->revision); + } +} + +const char *versiondescribe(const struct versionrevision *version, + enum versiondisplayepochwhen vdew) { + static struct varbuf bufs[10]; + static int bufnum=0; + + struct varbuf *vb; + + if (!informativeversion(version)) return ""; + + vb= &bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0; + varbufreset(vb); + varbufversion(vb,version,vdew); + varbufaddc(vb,0); + + return vb->buf; +} + +const char *parseversion(struct versionrevision *rversion, const char *string) { + char *hyphen, *colon, *eepochcolon; + unsigned long epoch; + + if (!*string) return "version string is empty"; + + colon= strchr(string,':'); + if (colon) { + epoch= strtoul(string,&eepochcolon,10); + if (colon != eepochcolon) return "epoch in version is not number"; + if (!*++colon) return "nothing after colon in version number"; + string= colon+1; + rversion->epoch= epoch; + } else { + rversion->epoch= 0; + } + rversion->version= nfstrsave(string); + hyphen= strrchr(rversion->version,'-'); + if (hyphen) *hyphen++= 0; + rversion->revision= hyphen ? hyphen : nfstrsave(""); + + return 0; +} + void parsemustfield(FILE *file, const char *filename, int lno, FILE *warnto, int *warncount, const struct pkginfo *pigp, int warnonly, diff --git a/lib/sta00630 b/lib/sta00630 new file mode 100644 index 0000000000000000000000000000000000000000..0cf064b618d825439f018937332b6c377cd074d5 GIT binary patch literal 167936 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 literal 0 HcmV?d00001 diff --git a/lib/varbuf.c b/lib/varbuf.c index 2f12db77..5d1785c5 100644 --- a/lib/varbuf.c +++ b/lib/varbuf.c @@ -30,6 +30,22 @@ void varbufaddc(struct varbuf *v, int c) { v->buf[v->used++]= c; } +void varbufprintf(struct varbuf *v, const char *fmt, ...) { + int ou, r; + va_list al; + + ou= v->used; + v->used+= strlen(fmt); + + do { + varbufextend(v); + va_start(al,fmt); + r= vsnprintf(v->buf+ou,v->size-ou,fmt,al); + va_end(al); + v->used= ou+r; + } while (r >= v->size-ou-1); +} + void varbufaddstr(struct varbuf *v, const char *s) { int l, ou; l= strlen(s); diff --git a/lib/vercmp.c b/lib/vercmp.c index a2fac63b..4dea53a9 100644 --- a/lib/vercmp.c +++ b/lib/vercmp.c @@ -27,6 +27,11 @@ #include "dpkg-db.h" #include "parsedump.h" +int epochsdiffer(const struct versionrevision *a, + const struct versionrevision *b) { + return a->epoch != b->epoch; +} + static int verrevcmp(const char *val, const char *ref) { int vc, rc; long vl, rl; @@ -56,9 +61,12 @@ static int verrevcmp(const char *val, const char *ref) { } } -int versioncompare(const char *version, const char *revision, - const char *refversion, const char *refrevision) { +int versioncompare(const struct versionrevision *version, + const struct versionrevision *refversion) { int r; - r= verrevcmp(version,refversion); if (r) return r; - return verrevcmp(revision,refrevision); + + if (version->epoch > refversion->epoch) return 1; + if (version->epoch < refversion->epoch) return 1; + r= verrevcmp(version->version,refversion->version); if (r) return r; + return verrevcmp(version->revision,refversion->revision); } diff --git a/main/archives.c b/main/archives.c index 7b17e208..fa1d286e 100644 --- a/main/archives.c +++ b/main/archives.c @@ -137,12 +137,12 @@ static int does_replace(struct pkginfo *newpigp, struct dependency *dep; debug(dbg_depcon,"does_replace new=%s old=%s (%s)",newpigp->name, - oldpigp->name,versiondescribe(oldpigp->installed.version, - oldpigp->installed.revision)); + oldpigp->name,versiondescribe(&oldpigp->installed.version, + vdew_always)); for (dep= newpifp->depends; dep; dep= dep->next) { if (dep->type != dep_replaces || dep->list->ed != oldpigp) continue; debug(dbg_depcondetail,"does_replace ... found old, version %s", - versiondescribe(dep->list->version,dep->list->revision)); + versiondescribe(&dep->list->version,vdew_always)); if (!versionsatisfied(&oldpigp->installed,dep->list)) continue; debug(dbg_depcon,"does_replace ... yes"); return 1; @@ -339,6 +339,11 @@ int tarobject(struct TarInfo *ti) { } /* Nope ? Hmm, file conflict, perhaps. Check Replaces. */ if (otherpkg->clientdata->replacingfilesandsaid) continue; + /* Is the package with the conflicting file in the `config files + * only' state ? If so it must be a config file and we can + * silenty take it over. + */ + if (otherpkg->status == stat_configfiles) continue; /* Perhaps we're removing a conflicting package ? */ if (otherpkg->clientdata->istobe == itb_remove) continue; if (does_replace(tc->pkg,&tc->pkg->available,otherpkg)) { @@ -547,75 +552,82 @@ void check_conflict(struct dependency *dep, struct pkginfo *pkg, varbuffree(&removalwhy); return; } - if (fixbyrm && - ((pkg->available.essential && fixbyrm->installed.essential) || - ((fixbyrm->want != want_install || does_replace(pkg,&pkg->available,fixbyrm)) && - (!fixbyrm->installed.essential || fc_removeessential)))) { + if (fixbyrm) { ensure_package_clientdata(fixbyrm); - assert(fixbyrm->clientdata->istobe == itb_normal); - fixbyrm->clientdata->istobe= itb_remove; - fprintf(stderr, DPKG ": considering removing %s in favour of %s ...\n", - fixbyrm->name, pkg->name); - if (fixbyrm->status != stat_installed) { - fprintf(stderr, - "%s is not properly installed - ignoring any dependencies on it.\n", - fixbyrm->name); - pdep= 0; - } else { - for (pdep= fixbyrm->installed.depended; - pdep; - pdep= pdep->nextrev) { - if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends) continue; - if (depisok(pdep->up, &removalwhy, 0,0)) continue; - varbufaddc(&removalwhy,0); - if (!try_remove_can(pdep,fixbyrm,removalwhy.buf)) - break; - } - if (!pdep) { - /* If we haven't found a reason not to yet, let's look some more. */ - for (providecheck= fixbyrm->installed.depends; - providecheck; - providecheck= providecheck->next) { - if (providecheck->type != dep_provides) continue; - for (pdep= providecheck->list->ed->installed.depended; - pdep; - pdep= pdep->nextrev) { - if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends) - continue; - if (depisok(pdep->up, &removalwhy, 0,0)) continue; - varbufaddc(&removalwhy,0); - fprintf(stderr, DPKG - ": may have trouble removing %s, as it provides %s ...\n", - fixbyrm->name, providecheck->list->ed->name); - if (!try_remove_can(pdep,fixbyrm,removalwhy.buf)) - goto break_from_both_loops_at_once; + if (fixbyrm->clientdata->istobe == itb_installnew) { + fixbyrm= dep->up; + ensure_package_clientdata(fixbyrm); + } + if (((pkg->available.essential && fixbyrm->installed.essential) || + (((fixbyrm->want != want_install && fixbyrm->want != want_hold) || + does_replace(pkg,&pkg->available,fixbyrm)) && + (!fixbyrm->installed.essential || fc_removeessential)))) { + assert(fixbyrm->clientdata->istobe == itb_normal); + fixbyrm->clientdata->istobe= itb_remove; + fprintf(stderr, DPKG ": considering removing %s in favour of %s ...\n", + fixbyrm->name, pkg->name); + if (fixbyrm->status != stat_installed) { + fprintf(stderr, + "%s is not properly installed - ignoring any dependencies on it.\n", + fixbyrm->name); + pdep= 0; + } else { + for (pdep= fixbyrm->installed.depended; + pdep; + pdep= pdep->nextrev) { + if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends) + continue; + if (depisok(pdep->up, &removalwhy, 0,0)) continue; + varbufaddc(&removalwhy,0); + if (!try_remove_can(pdep,fixbyrm,removalwhy.buf)) + break; + } + if (!pdep) { + /* If we haven't found a reason not to yet, let's look some more. */ + for (providecheck= fixbyrm->installed.depends; + providecheck; + providecheck= providecheck->next) { + if (providecheck->type != dep_provides) continue; + for (pdep= providecheck->list->ed->installed.depended; + pdep; + pdep= pdep->nextrev) { + if (pdep->up->type != dep_depends && pdep->up->type != dep_predepends) + continue; + if (depisok(pdep->up, &removalwhy, 0,0)) continue; + varbufaddc(&removalwhy,0); + fprintf(stderr, DPKG + ": may have trouble removing %s, as it provides %s ...\n", + fixbyrm->name, providecheck->list->ed->name); + if (!try_remove_can(pdep,fixbyrm,removalwhy.buf)) + goto break_from_both_loops_at_once; + } } + break_from_both_loops_at_once:; } - break_from_both_loops_at_once:; } - } - if (!pdep && skip_due_to_hold(fixbyrm)) { - pdep= &flagdeppossi; - } - if (!pdep && (fixbyrm->eflag & eflagf_reinstreq)) { - if (fc_removereinstreq) { - fprintf(stderr, DPKG ": package %s requires reinstallation, but will" - " remove anyway as you request.\n", fixbyrm->name); - } else { - fprintf(stderr, DPKG ": package %s requires reinstallation, will not remove.\n", - fixbyrm->name); + if (!pdep && skip_due_to_hold(fixbyrm)) { pdep= &flagdeppossi; } + if (!pdep && (fixbyrm->eflag & eflagf_reinstreq)) { + if (fc_removereinstreq) { + fprintf(stderr, DPKG ": package %s requires reinstallation, but will" + " remove anyway as you request.\n", fixbyrm->name); + } else { + fprintf(stderr, DPKG ": package %s requires reinstallation, " + "will not remove.\n", fixbyrm->name); + pdep= &flagdeppossi; + } + } + if (!pdep) { + /* This conflict is OK - we'll remove the conflictor. */ + *conflictorp= fixbyrm; + varbuffree(&conflictwhy); varbuffree(&removalwhy); + fprintf(stderr, DPKG ": yes, will remove %s in favour of %s.\n", + fixbyrm->name, pkg->name); + return; + } + fixbyrm->clientdata->istobe= itb_normal; /* put it back */ } - if (!pdep) { - /* This conflict is OK - we'll remove the conflictor. */ - *conflictorp= fixbyrm; - varbuffree(&conflictwhy); varbuffree(&removalwhy); - fprintf(stderr, DPKG ": yes, will remove %s in favour of %s.\n", - fixbyrm->name, pkg->name); - return; - } - fixbyrm->clientdata->istobe= itb_normal; /* put it back */ } varbufaddc(&conflictwhy,0); fprintf(stderr, DPKG ": regarding %s containing %s:\n%s", diff --git a/main/cleanup.c b/main/cleanup.c index b12e3cf1..a7057805 100644 --- a/main/cleanup.c +++ b/main/cleanup.c @@ -104,8 +104,8 @@ void cu_prermupgrade(int argc, void **argv) { if (cleanup_pkg_failed++) return; maintainer_script_installed(pkg,POSTINSTFILE,"post-installation", "abort-upgrade", - versiondescribe(pkg->available.version, - pkg->available.revision), + versiondescribe(&pkg->available.version, + vdew_nonambig), (char*)0); pkg->status= stat_installed; pkg->eflag &= ~eflagf_reinstreq; @@ -128,11 +128,11 @@ void cu_prermdeconfigure(int argc, void **argv) { maintainer_script_installed(deconf,POSTINSTFILE,"post-installation", "abort-deconfigure", "in-favour", infavour->name, - versiondescribe(infavour->available.version, - infavour->available.revision), + versiondescribe(&infavour->available.version, + vdew_nonambig), "removing", conflictor->name, - versiondescribe(conflictor->installed.version, - conflictor->installed.revision), + versiondescribe(&conflictor->installed.version, + vdew_nonambig), (char*)0); deconf->status= stat_installed; modstatdb_note(deconf); @@ -145,8 +145,8 @@ void cu_prerminfavour(int argc, void **argv) { if (cleanup_conflictor_failed++) return; maintainer_script_installed(conflictor,POSTINSTFILE,"post-installation", "abort-remove", "in-favour", infavour->name, - versiondescribe(infavour->available.version, - infavour->available.revision), + versiondescribe(&infavour->available.version, + vdew_nonambig), (char*)0); conflictor->status= stat_installed; conflictor->eflag &= ~eflagf_reinstreq; @@ -175,8 +175,8 @@ void cu_preinstnew(int argc, void **argv) { if (cleanup_pkg_failed++) return; maintainer_script_new(POSTRMFILE,"post-removal",cidir,cidirrest, - "abort-install", versiondescribe(pkg->installed.version, - pkg->installed.revision), + "abort-install", versiondescribe(&pkg->installed.version, + vdew_nonambig), (char*)0); pkg->status= stat_configfiles; pkg->eflag &= ~eflagf_reinstreq; @@ -193,8 +193,8 @@ void cu_preinstupgrade(int argc, void **argv) { if (cleanup_pkg_failed++) return; maintainer_script_new(POSTRMFILE,"post-removal",cidir,cidirrest, "abort-upgrade", - versiondescribe(pkg->installed.version, - pkg->installed.revision), + versiondescribe(&pkg->installed.version, + vdew_nonambig), (char*)0); pkg->status= *oldstatusp; pkg->eflag &= ~eflagf_reinstreq; @@ -207,8 +207,8 @@ void cu_postrmupgrade(int argc, void **argv) { if (cleanup_pkg_failed++) return; maintainer_script_installed(pkg,PREINSTFILE,"pre-installation", - "abort-upgrade", versiondescribe(pkg->available.version, - pkg->available.revision), + "abort-upgrade", versiondescribe(&pkg->available.version, + vdew_nonambig), (char*)0); cleanup_pkg_failed--; } diff --git a/main/configure.c b/main/configure.c index 6ec20cfe..f56348bd 100644 --- a/main/configure.c +++ b/main/configure.c @@ -378,8 +378,8 @@ void deferred_configure(struct pkginfo *pkg) { if (maintainer_script_installed(pkg, POSTINSTFILE, "post-installation", "configure", - versiondescribe(pkg->configversion, - pkg->configrevision), + versiondescribe(&pkg->configversion, + vdew_nonambig), (char*)0)) putchar('\n'); diff --git a/main/depcon.c b/main/depcon.c index 7e90464a..389ff4da 100644 --- a/main/depcon.c +++ b/main/depcon.c @@ -30,12 +30,12 @@ #include "main.h" -int versionsatisfied5(const char *itver, const char *itrev, - const char *refver, const char *refrev, +int versionsatisfied3(const struct versionrevision *it, + const struct versionrevision *ref, enum depverrel verrel) { int r; if (verrel == dvr_none) return 1; - r= versioncompare(itver,itrev,refver,refrev); + r= versioncompare(it,ref); switch (verrel) { case dvr_earlierequal: return r <= 0; case dvr_laterequal: return r >= 0; @@ -47,27 +47,7 @@ int versionsatisfied5(const char *itver, const char *itrev, } int versionsatisfied(struct pkginfoperfile *it, struct deppossi *against) { - return versionsatisfied5(it->version, it->revision, - against->version, against->revision, against->verrel); -} - -const char *versiondescribe(const char *ver, const char *rev) { - static char bufs[10][512]; - static int bufnum=0; - char *buf; - - buf= bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0; - - if (!ver || !*ver) { - strcpy(buf,""); - } else { - if (rev && *rev) { - sprintf(buf, "%.250s-%.250s", ver, rev); - } else { - sprintf(buf, "%.250s", ver); - } - } - return buf; + return versionsatisfied3(&it->version,&against->version,against->verrel); } struct cyclesofarlink { @@ -245,30 +225,28 @@ int depisok(struct dependency *dep, struct varbuf *whynot, * the end we'll have accumulated all the reasons in whynot and * can return `0'. */ - + for (possi= dep->list; possi; possi= possi->next) { switch (possi->ed->clientdata->istobe) { case itb_remove: - sprintf(linebuf, " %.250s is to be removed.\n", possi->ed->name); + sprintf(linebuf," %.250s is to be removed.\n",possi->ed->name); break; case itb_deconfigure: - sprintf(linebuf, " %.250s is to be deconfigured.\n", possi->ed->name); + sprintf(linebuf," %.250s is to be deconfigured.\n",possi->ed->name); break; case itb_installnew: - if (versionsatisfied(&possi->ed->available, possi)) return 1; - sprintf(linebuf, " %.250s is to be installed, but is version %.250s.\n", + if (versionsatisfied(&possi->ed->available,possi)) return 1; + sprintf(linebuf," %.250s is to be installed, but is version %.250s.\n", possi->ed->name, - versiondescribe(possi->ed->available.version, - possi->ed->available.revision)); + versiondescribe(&possi->ed->available.version,vdew_nonambig)); break; case itb_normal: case itb_preinstall: switch (possi->ed->status) { case stat_installed: - if (versionsatisfied(&possi->ed->installed, possi)) return 1; - sprintf(linebuf, " %.250s is installed, but is version %.250s.\n", + if (versionsatisfied(&possi->ed->installed,possi)) return 1; + sprintf(linebuf," %.250s is installed, but is version %.250s.\n", possi->ed->name, - versiondescribe(possi->ed->available.version, - possi->ed->available.revision)); + versiondescribe(&possi->ed->installed.version,vdew_nonambig)); break; case stat_notinstalled: /* Don't say anything about this yet - it might be a virtual package. @@ -280,24 +258,20 @@ int depisok(struct dependency *dep, struct varbuf *whynot, case stat_unpacked: case stat_halfconfigured: if (allowunconfigd) { - if (!possi->ed->configversion || !*possi->ed->configversion) { + if (!informativeversion(&possi->ed->configversion)) { sprintf(linebuf, " %.250s is unpacked, but has never been configured.\n", possi->ed->name); break; } else if (!versionsatisfied(&possi->ed->installed, possi)) { sprintf(linebuf, " %.250s is unpacked, but is version %.250s.\n", possi->ed->name, - versiondescribe(possi->ed->available.version, - possi->ed->available.revision)); + versiondescribe(&possi->ed->available.version,vdew_nonambig)); break; - } else if (!versionsatisfied5(possi->ed->configversion, - possi->ed->configrevision, - possi->version, possi->revision, - possi->verrel)) { + } else if (!versionsatisfied3(&possi->ed->configversion, + &possi->version,possi->verrel)) { sprintf(linebuf, " %.250s latest configured version is %.250s.\n", possi->ed->name, - versiondescribe(possi->ed->configversion, - possi->ed->configrevision)); + versiondescribe(&possi->ed->configversion,vdew_nonambig)); break; } else { return 1; @@ -396,8 +370,7 @@ int depisok(struct dependency *dep, struct varbuf *whynot, if (!versionsatisfied(&possi->ed->available, possi)) break; sprintf(linebuf, " %.250s (version %.250s) is to be installed.\n", possi->ed->name, - versiondescribe(possi->ed->available.version, - possi->ed->available.revision)); + versiondescribe(&possi->ed->available.version,vdew_nonambig)); varbufaddstr(whynot, linebuf); if (!canfixbyremove) return 0; nconflicts++; @@ -411,8 +384,7 @@ int depisok(struct dependency *dep, struct varbuf *whynot, if (!versionsatisfied(&possi->ed->installed, possi)) break; sprintf(linebuf, " %.250s (version %.250s) is %s.\n", possi->ed->name, - versiondescribe(possi->ed->available.version, - possi->ed->available.revision), + versiondescribe(&possi->ed->installed.version,vdew_nonambig), statusstrings[possi->ed->status]); varbufaddstr(whynot, linebuf); if (!canfixbyremove) return 0; @@ -455,8 +427,8 @@ int depisok(struct dependency *dep, struct varbuf *whynot, case itb_installnew: /* Don't pay any attention to the Provides field of the * currently-installed version of the package we're trying - * to install. We dealt with that by using the available - * information above. + * to install. We dealt with that package by using the + * available information above. */ continue; case itb_remove: diff --git a/main/dpkg.8 b/main/dpkg.8 index bf760f43..9d4de130 100644 --- a/main/dpkg.8 +++ b/main/dpkg.8 @@ -1,20 +1,613 @@ -.\" Hey, Emacs! This is an -*- nroff -*- source file. -.TH DPKG 8 "29th November 1995" "Debian Project" "Debian GNU/Linux" +.TH dpkg 8 .SH NAME -dpkg \- Debian package installation tool +dpkg - a low-level package manager for Debian GNU/Linux + +.SH SYNOPSIS + +.B dpkg +[options] action + +.SH WARNING WARNING WARNING + +This manual was inaccurate when it was written and is now also out of +date. + +It should +.I not +be used by package maintainers wishing to understand how +.B dpkg +will install their packages. + +It may be useful to users wishing to understand +.BR "dpkg"'s +command line options and package states in more detail than that +provided by +.BR "dpkg --help" . + +The descriptions of what +.B dpkg +does when installing and removing packages are particularly +inadequate. For detailed information about this please refer to the +Debian Packaging Guidelines, available under +.I guidelines +in the GNU Info system. + .SH DESCRIPTION + +.B dpkg +is a medium-level tool to install, build, remove and manage Debian +GNU/Linux packages. The primary and more user-friendly front-end +for .B dpkg -does not have a useful man page. Please do not report this as a bug, -as this has already been done many times. +is +.B dselect(8). +.B dpkg +itself is totally controlled via command line parameters, whose include +one or more options and exactly one action. The action-parameter tells +dpkg what to do and options control the behaviour of the action in some +way. + +.B dpkg +can be also be used as a front-end to +.B dpkg-deb. +Actions +.B -b +, +.B --build +, +.B -c +, +.B --contents +, +.B -I +, +.B --info +, +.B -f +, +.B --field +, +.B -e +, +.B --control +, +.B -x +, +.B --extract +, +.B -X +, +.B --vextract +and +.B --fsys-tarfile +are +.B dpkg-deb +actions and if they are encountered, +.B dpkg +just runs +.B dpkg-deb +with the parameters given to it. Please refer to +.B dpkg-deb(8) +for information about these actions. + +.SS ACTIONS + +.TP +.B dpkg -i | --install ... +Install specified packages. If +.B --recursive +or +.B -R +option is specified, +.I +must refer to a directory instead. + +Installation consists of the following steps: +.br +.B 1. +Extract the controlfiles of the new package. +.br +.B 2. +If another version of the same package was installed before the +new installation, execute +.I prerm +script of the old package. +.br +.B 3. +Run +.I preinst +script, if provided by the package. +.br +.B 4. +Unpack the files and at the same time, backup the old files +so that if something goes wrong, we can restore them. +.br +.B 5. +If another version of the same package was installed before +the new installation, execute the +.I postrm +script of the old package. Note that this script is executed after the +.I preinst +script of the new package, because new files are written at the same +time, old files are removed. +.br +.B 6. +eonfigure the package. See +.B --configure +for detailed information about how this is done. +.TP +.B dpkg --unpack ... +Unpack package, but don't configure it. If +.B --recursive +or +.B -R +option is specified, +.I +must refer to a directory instead. +.TP +.B dpkg --configure ... | -a|--pending +Reconfigure an unpacked package. +If +.B -a +or +.B --pending +is given instead of package name, all unpacked, but unconfigured +packages are configured. + +Configuring consists of the following steps: +.br +.B 1. +Unpack the configuration files and at the same time, backup the old +configuration files, so that we can restore them, if +something goes +wrong. +.br +.B 2. +Run +.I postinst +script, if provided by the package. +.TP +.B dpkg -r|--remove | --purge ... | -a|--pending +Remove an installed package. +.B --purge +removes everything, including configuration files, +.B --remove +removes everything, but not configuration files. (configuration files are +the files listed in +.I conffiles +-control file). If +.B -a +or +.B --pending +is given instead of package name all packages unpacked, but marked to be +removed or purged are removed or purged (in file +.I /var/lib/dpkg/status +). + +Removing of a package consists of the following steps: +.br +.B 1. +Run prerm script +.br +.B 2. +Remove the installed files +.br +.B 3. +Run postrm script +.br +.TP +.B dpkg -A | --avail ... +Update +.B dpkg +and +.B dselect's +idea of which packages are available with information about the package +.I . +If +.B --recursive +or +.B -R +option is specified, +.I +must refer to a directory instead. +.TP +.B dpkg --update-avail | --merge-avail +Update +.B dpkg's +and +.B dselect's +idea of which packages are available. With action +.B --merge-avail, +information is combined from the old information and from the +.I . +With action +.B --update-avail, +old information is replaced with the information in the +.I . +The +.I +distributed with Debian GNU/Linux is simply named +.I Packages. +.TP +.B dpkg --yet-to-unpack +Searches for packages selected for installation, but which for some +reason still haven't been installed. +.TP +.B dpkg -l|--list [ ...] +List packages matching given pattern. If no +.B +is given, list all packages in +.I /var/lib/dpkg/available. +Normal shell wildchars are allowed in +.B . +.TP +.B dpkg -L|--listfiles ... +List files installed to your system from a package +.B . +However, note that files created by package-specific +installation-scripts are not listed. +.TP +.B dpkg -C|--audit +Searches for packages that have been installed only partially on your +system. +.B dpkg +will suggest what to do with them to get them working. +.TP +.B dpkg -S|--search ... +Search for a filename from installed packages. All standard shell +wildchars can be used in the pattern. +.TP +.B dpkg -s|--status ... +Report status of specified package. This just displays the entry in from +the installed package status database. +.TP +.B dpkg --help +Display a brief help. +.TP +.B dpkg --licence +Display licence of +.B dpkg. +.TP +.B dpkg --version +Display version information. +.TP +.B dpkg-deb-actions +See +.B dpkg-deb(8) +for more information about these actions. + +.B dpkg -b|--build [] +- Build a Debian GNU/Linux package. +.br +.B dpkg -c|--contents +- List contents of Debian GNU/Linux package. +.br +.B dpkg -e|--control [] +- Extract control-information from a package. +.br +.B dpkg -x|--extract +- Extract the files contained by package. +.br +.B dpkg -f|--field [...] +- Display control field(s) of a package. +.br +.B dpkg --fsys-tarfile +- Display the filesystem tar-file contained by a Debian package. +.br +.B dpkg -I|--info [] +- Show information about a package. +.br +.B dpkg -X|--vextract +- Extract and display the filenames contained by a package. -Instead, if you are a competent and accurate writer and are willing to -spend the time reading the source code and writing good manpages -please write a better man page than this one. +.SS OPTIONS -Type -.B dpkg \-\-help -for a brief summary of how to use dpkg. +.TP +.B -B | --auto-deconfigure +While a package is removed, there is a possibility that another +installed package depended on the removed package. Specifying this +option will cause automatical deconfiguration of the package which +depended on the removed package. +.TP +.B -Dh | --debug=help +Give help about debugging options. +.TP +.B -D | --debug= +Set debugging on. +.B +is a octal number formed by bitwise-orring desired values together from +the list below (note that these values may change in future releases). + number description + 1 Generally helpful progress information + 2 Invocation and status of maintainer scripts + 10 Output for each file processed + 100 Lots of output for each file processed + 20 Output for each configuration file + 200 Lots of output for each configuration file + 40 Dependencies and conflicts + 400 Lots of dependencies/conflicts output + 1000 Lots of drivel about eg the dpkg/info dir + 2000 Insane amounts of drivel +.TP +.B --force- | --no-force- | --refuse- +Force or refuse (no-force and refuse stands for the same thing) to do +some things. +.B +is a comma separated list of things specified below: + +.I downgrade(*): +Install a package, even if newer version of it is already installed. + +.I configure-any: +Configure also unpacked, but unconfigured packages on whose current +package depends on. + +.I remove-reinstreq: +Remove a package, even if it's broken and marked to require +reinstallation. This may, for example, cause parts of the package to +remain on the system, which will then be forgotten by +.B dpkg. + +.I hold: +Don't care, wheter a package is on hold or not. + +.I remove-essential: +Remove, even if the package is considered essential. Essential packages +contains mostly very basic unix commands and such. Removing them might +cause the whole system to stop working, so use with caution. + +.I conflicts: +Install, even if it conflicts with another package. This is dangerous, +for it will usually cause overwriting of some files. + +.I depends: +Remove, even if another package depends on this one. This will usually +break the other package. + +.I depends-version: +Don't care about versions when checking depencies. This will usually +break the other package. + +Things marked with (*) are forced by default. +.I Warning: +These options are mostly intended to be used by experts only. Using them +without fully understanding their effects may break your whole system. + +.TP +.B --ignore-depends=,... +Ignore depency-checking for specified packages (actually, checking is +performed, but only warnings about conflicts are given, nothing else). +.TP +.B --largemem | --smallmem +Tells +.B dpkg +wheter to preserve memory or consume it as much as needed. +.TP +.B --new | --old +Select new or old package format. This is a +.B dpkg-deb(8) +option. +.TP +.B --nocheck +Don't read or check contents of control file while building a package. +This is a +.B dpkg-deb(8) +option. +.TP +.B --no-act +Do everything, which is supposed to be done, but don't write any +changes. This is used to see, what would happen with specified action, +without actually modifying anything. + +Be sure to give +.B --no-act +before action-parameter, or you might end up with undesirable results. +(e.g. +.B dpkg --purge foo --no-act +will first purge package foo and then try to purge package --no-act, +even though you propably expected it to actually do nothing) +.TP +.B -R | --recursive +Recursively handle all regular files matching pattern +.I *.deb +found at specified directories and all of its subdirectories. This +can be used with +.B -i +, +.B -A +, +.B --install +, +.B --unpack +and +.B --avail +actions. +.TP +.B -G +Don't install package, if newer version of the same package is already +installed. This is an alias to +.B--refuse-downgrade. +.TP +.B -R|--root= | --admindir= | --instdir= +Change default directories. +.B admindir +defaults to +.I /var/lib/dpkg +and contains many files that give information about status of installed +or uninstalled packages, etc. +.B instdir +defaults to +.I / +and refers to the directory where packages are to be installed. +.B instdir +is also the directory passed to +.B chroot(2) +before running package's installation scripts, which means that the +scripts see +.B instdir +as a root directory. +Changing +.B root +changes +.B instdir +to +.I +and +.B admindir +to +.I /var/lib/dpkg. +.TP +.B -O | --selected-only +Only process the packages that are selected for installation. The actual +marking is done with +.B dselect +or by +.B dpkg, +when it handles packages. i.e. When, for example a package is removed, +it will be marked selected for installation, etc. +.TP +.B -E | --skip-same-version +Don't install the package, if the same version of the package is already +installed. + +.SH INFORMATION ABOUT PACKAGES +.B dpkg +maintains some usable information about available packages. The +information is divided in three classes: +.B states +, +.B selection states +and +.B flags. +These values are intended to be changed mainly with +.B dselect. +.SS PACKAGE STATES +.TP +.B installed +The package is unpacked and configured ok. +.TP +.B half-installed +The installation of the package has been started, but not completed for +some reason. +.TP +.B not-installed +The package is not installed on your system. +.TP +.B unpacked +The package is unpacked, but not configured. +.TP +.B half-configured +The package is unpacked and configuration has been started, but not yet +completed for some reason. +.TP +.B config-files +Only the configuration files of the package exist on the system. +.SS PACKAGE SELECTION STATES +.TP +.B install +The package is selected for installation. +.TP +.B deinstall +The package is selected for deinstallation (i.e. we want to remove all +files, except configuration files). +.TP +.B purge +The package is selected to be purged (i.e. we want to remove everything, +even configuration files). +.SS PACKAGE FLAGS +.TP +.B hold +A package marked to be on +.B hold +is not handled by +.B dpkg, +unless forced to do that with option +.B --force-hold. +.TP +.B reinst-required +A package marked +.B reinst-required +is broken and requires reinstallation. These packages cannot be removed, +unless forced with option +.B --force-reinstreq. + +.SH FILES +The files listed here are in their default directories, see option +.B --admindir +to see how to change locations of these files. +.TP +.I /var/lib/dpkg/available +List of available packages. +.TP +.I /var/lib/dpkg/status +Statuses of available packages. This file contains information about +wheter a package is marked for removing or not, wheter it is installed +or not, etc. See section +.B INFORMATION ABOUT PACKAGES +for more info. +.TP +.I control +See +.B deb(5) +for more information about this file. +.TP +.I conffiles +.B dpkg. +See +.B deb(5) +for more information about this file. +.TP +.I preinst +See +.B deb(5) +for more information about this file. +.TP +.I postinst +See +.B deb(5) +for more information about this file. +.TP +.I prerm +See +.B deb(5) +for more information about this file. +.TP +.I postrm +See +.B deb(5) +for more information about this file. + +.SH ENVIRONMENT VARIABLES +.TP +.B DPKG_NO_TSTP +Define this to something, if you prefer +.B dpkg +starting a new shell rather than suspending +.B dpkg, +while doing a shell escape. +.TP +.B SHELL +The program +.B dpkg +will execute while starting a new shell. + +.SH SEE ALSO +.B deb(5) +, +.B dpkg-deb(8) +, +.B dselect(8) +and +.B deb-control(5) + +.SH BUGS + +.B --no-act +usually gives less information that might be helpful. .SH AUTHOR -Ian Jackson ; tarfile extraction code -contributed by Bruce Perens . +.B dpkg +is written by Ian Jackson (ian@chiark.chu.cam.ac.uk). Manual page added +by Juho Vuori (javuori@cc.helsinki.fi). + + diff --git a/main/dpkg.8-null b/main/dpkg.8-null new file mode 100644 index 00000000..bf760f43 --- /dev/null +++ b/main/dpkg.8-null @@ -0,0 +1,20 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.TH DPKG 8 "29th November 1995" "Debian Project" "Debian GNU/Linux" +.SH NAME +dpkg \- Debian package installation tool +.SH DESCRIPTION +.B dpkg +does not have a useful man page. Please do not report this as a bug, +as this has already been done many times. + +Instead, if you are a competent and accurate writer and are willing to +spend the time reading the source code and writing good manpages +please write a better man page than this one. + +Type +.B dpkg \-\-help +for a brief summary of how to use dpkg. + +.SH AUTHOR +Ian Jackson ; tarfile extraction code +contributed by Bruce Perens . diff --git a/main/dpkg.8-vuori b/main/dpkg.8-vuori deleted file mode 100644 index 18cc4c0f..00000000 --- a/main/dpkg.8-vuori +++ /dev/null @@ -1,588 +0,0 @@ -.TH dpkg 8 -.SH NAME -dpkg - a low-level package manager for Debian GNU/Linux - -.SH SYNOPSIS - -.B dpkb -[options] action - -.SH DESCRIPTION - -.B dpkg -is a medium-level tool to install, build, remove and manage Debian -GNU/Linux packages. The primary and more user-friendly front-end -for -.B dpkg -is -.B dselect(8). -.B dpkg -itself is totally controlled via command line parameters, whose include -one or more options and exactly one action. The action-parameter tells -dpkg what to do and options control the behaviour of the action in some -way. - -.B dpkg -can be also be used as a front-end to -.B dpkg-deb. -Actions -.B -b -, -.B --build -, -.B -c -, -.B --contents -, -.B -I -, -.B --info -, -.B -f -, -.B --field -, -.B -e -, -.B --control -, -.B -x -, -.B --extract -, -.B -X -, -.B --vextract -and -.B --fsys-tarfile -are -.B dpkg-deb -actions and if they are encountered, -.B dpkg -just runs -.B dpkg-deb -with the parameters given to it. Please refer to -.B dpkg-deb(8) -for information about these actions. - -.SS ACTIONS - -.TP -.B dpkg -i | --install ... -Install specified packages. If -.B --recursive -or -.B -R -option is specified, -.I -must refer to a directory instead. - -Installation consists of the following steps: -.br -.B 1. -Extract the controlfiles of the new package. -.br -.B 2. -If another version of the same package was installed before the -new installation, execute -.I prerm -script of the old package. -.br -.B 3. -Run -.I preinst -script, if provided by the package. -.br -.B 4. -Unpack the files and at the same time, backup the old files -so that if something goes wrong, we can restore them. -.br -.B 5. -If another version of the same package was installed before -the new installation, execute the -.I postrm -script of the old package. Note that this script is executed after the -.I preinst -script of the new package, because new files are written at the same -time, old files are removed. -.br -.B 6. -eonfigure the package. See -.B --configure -for detailed information about how this is done. -.TP -.B dpkg --unpack ... -Unpack package, but don't configure it. If -.B --recursive -or -.B -R -option is specified, -.I -must refer to a directory instead. -.TP -.B dpkg --configure ... | -a|--pending -Reconfigure an unpacked package. -If -.B -a -or -.B --pending -is given instead of package name, all unpacked, but unconfigured -packages are configured. - -Configuring consists of the following steps: -.br -.B 1. -Unpack the configuration files and at the same time, backup the old -configuration files, so that we can restore them, if -something goes -wrong. -.br -.B 2. -Run -.I postinst -script, if provided by the package. -.TP -.B dpkg -r|--remove | --purge ... | -a|--pending -Remove an installed package. -.B --purge -removes everything, including configuration files, -.B --remove -removes everything, but not configuration files. (configuration files are -the files listed in -.I conffiles --control file). If -.B -a -or -.B --pending -is given instead of package name all packages unpacked, but marked to be -removed or purged are removed or purged (in file -.I /var/lib/dpkg/status -). - -Removing of a package consists of the following steps: -.br -.B 1. -Run prerm script -.br -.B 2. -Remove the installed files -.br -.B 3. -Run postrm script -.br -.TP -.B dpkg -A | --avail ... -Update -.B dpkg -and -.B dselect's -idea of which packages are available with information about the package -.I . -If -.B --recursive -or -.B -R -option is specified, -.I -must refer to a directory instead. -.TP -.B dpkg --update-avail | --merge-avail -Update -.B dpkg's -and -.B dselect's -idea of which packages are available. With action -.B --merge-avail, -information is combined from the old information and from the -.I . -With action -.B --update-avail, -old information is replaced with the information in the -.I . -The -.I -distributed with Debian GNU/Linux is simply named -.I Packages. -.TP -.B dpkg --yet-to-unpack -Searches for packages selected for installation, but which for some -reason still haven't been installed. -.TP -.B dpkg -l|--list [ ...] -List packages matching given pattern. If no -.B -is given, list all packages in -.I /var/lib/dpkg/available. -Normal shell wildchars are allowed in -.B . -.TP -.B dpkg -L|--listfiles ... -List files installed to your system from a package -.B . -However, note that files created by package-specific -installation-scripts are not listed. -.TP -.B dpkg -C|--audit -Searches for packages that have been installed only partially on your -system. -.B dpkg -will suggest what to do with them to get them working. -.TP -.B dpkg -S|--search ... -Search for a filename from installed packages. All standard shell -wildchars can be used in the pattern. -.TP -.B dpkg -s|--status ... -Report status of specified package. This just displays the entry in from -the installed package status database. -.TP -.B dpkg --help -Display a brief help. -.TP -.B dpkg --licence -Display licence of -.B dpkg. -.TP -.B dpkg --version -Display version information. -.TP -.B dpkg-deb-actions -See -.B dpkg-deb(8) -for more information about these actions. - -.B dpkg -b|--build [] -- Build a Debian GNU/Linux package. -.br -.B dpkg -c|--contents -- List contents of Debian GNU/Linux package. -.br -.B dpkg -e|--control [] -- Extract control-information from a package. -.br -.B dpkg -x|--extract -- Extract the files contained by package. -.br -.B dpkg -f|--field [...] -- Display control field(s) of a package. -.br -.B dpkg --fsys-tarfile -- Display the filesystem tar-file contained by a Debian package. -.br -.B dpkg -I|--info [] -- Show information about a package. -.br -.B dpkg -X|--vextract -- Extract and display the filenames contained by a package. - -.SS OPTIONS - -.TP -.B -B | --auto-deconfigure -While a package is removed, there is a possibility that another -installed package depended on the removed package. Specifying this -option will cause automatical deconfiguration of the package which -depended on the removed package. -.TP -.B -Dh | --debug=help -Give help about debugging options. -.TP -.B -D | --debug= -Set debugging on. -.B -is a octal number formed by bitwise-orring desired values together from -the list below (note that these values may change in future releases). - - number description - 1 Generally helpful progress information - 2 Invocation and status of maintainer scripts - 10 Output for each file processed - 100 Lots of output for each file processed - 20 Output for each configuration file - 200 Lots of output for each configuration file - 40 Dependencies and conflicts - 400 Lots of dependencies/conflicts output - 1000 Lots of drivel about eg the dpkg/info dir - 2000 Insane amounts of drivel -.TP -.B --force- | --no-force- | --refuse- -Force or refuse (no-force and refuse stands for the same thing) to do -some things. -.B -is a comma separated list of things specified below: - -.I downgrade(*): -Install a package, even if newer version of it is already installed. - -.I configure-any: -Configure also unpacked, but unconfigured packages on whose current -package depends on. - -.I remove-reinstreq: -Remove a package, even if it's broken and marked to require -reinstallation. This may, for example, cause parts of the package to -remain on the system, which will then be forgotten by -.B dpkg. - -.I hold: -Don't care, wheter a package is on hold or not. - -.I remove-essential: -Remove, even if the package is considered essential. Essential packages -contains mostly very basic unix commands and such. Removing them might -cause the whole system to stop working, so use with caution. - -.I conflicts: -Install, even if it conflicts with another package. This is dangerous, -for it will usually cause overwriting of some files. - -.I depends: -Remove, even if another package depends on this one. This will usually -break the other package. - -.I depends-version: -Don't care about versions when checking depencies. This will usually -break the other package. - -Things marked with (*) are forced by default. -.I Warning: -These options are mostly intended to be used by experts only. Using them -without fully understanding their effects may break your whole system. - -.TP -.B --ignore-depends=,... -Ignore depency-checking for specified packages (actually, checking is -performed, but only warnings about conflicts are given, nothing else). -.TP -.B --largemem | --smallmem -Tells -.B dpkg -wheter to preserve memory or consume it as much as needed. -.TP -.B --new | --old -Select new or old package format. This is a -.B dpkg-deb(8) -option. -.TP -.B --nocheck -Don't read or check contents of control file while building a package. -This is a -.B dpkg-deb(8) -option. -.TP -.B --no-act -Do everything, which is supposed to be done, but don't write any -changes. This is used to see, what would happen with specified action, -without actually modifying anything. - -Be sure to give -.B --no-act -before action-parameter, or you might end up with undesirable results. -(e.g. -.B dpkg --purge foo --no-act -will first purge package foo and then try to purge package --no-act, -even though you propably expected it to actually do nothing) -.TP -.B -R | --recursive -Recursively handle all regular files matching pattern -.I *.deb -found at specified directories and all of its subdirectories. This -can be used with -.B -i -, -.B -A -, -.B --install -, -.B --unpack -and -.B --avail -actions. -.TP -.B -G -Don't install package, if newer version of the same package is already -installed. This is an alias to -.B--refuse-downgrade. -.TP -.B -R|--root= | --admindir= | --instdir= -Change default directories. -.B admindir -defaults to -.I /var/lib/dpkg -and contains many files that give information about status of installed -or uninstalled packages, etc. -.B instdir -defaults to -.I / -and refers to the directory where packages are to be installed. -.B instdir -is also the directory passed to -.B chroot(2) -before running package's installation scripts, which means that the -scripts see -.B instdir -as a root directory. -Changing -.B root -changes -.B instdir -to -.I -and -.B admindir -to -.I /var/lib/dpkg. -.TP -.B -O | --selected-only -Only process the packages that are selected for installation. The actual -marking is done with -.B dselect -or by -.B dpkg, -when it handles packages. i.e. When, for example a package is removed, -it will be marked selected for installation, etc. -.TP -.B -E | --skip-same-version -Don't install the package, if the same version of the package is already -installed. - -.SH INFORMATION ABOUT PACKAGES -.B dpkg -maintains some usable information about available packages. The -information is divided in three classes: -.B states -, -.B selection states -and -.B flags. -These values are intended to be changed mainly with -.B dselect. -.SS PACKAGE STATES -.TP -.B installed -The package is unpacked and configured ok. -.TP -.B half-installed -The installation of the package has been started, but not completed for -some reason. -.TP -.B not-installed -The package is not installed on your system. -.TP -.B unpacked -The package is unpacked, but not configured. -.TP -.B half-configured -The package is unpacked and configuration has been started, but not yet -completed for some reason. -.TP -.B config-files -Only the configuration files of the package exist on the system. -.SS PACKAGE SELECTION STATES -.TP -.B install -The package is selected for installation. -.TP -.B deinstall -The package is selected for deinstallation (i.e. we want to remove all -files, except configuration files). -.TP -.B purge -The package is selected to be purged (i.e. we want to remove everything, -even configuration files). -.SS PACKAGE FLAGS -.TP -.B hold -A package marked to be on -.B hold -is not handled by -.B dpkg, -unless forced to do that with option -.B --force-hold. -.TP -.B reinst-required -A package marked -.B reinst-required -is broken and requires reinstallation. These packages cannot be removed, -unless forced with option -.B --force-reinstreq. - -.SH FILES -The files listed here are in their default directories, see option -.B --admindir -to see how to change locations of these files. -.TP -.I /var/lib/dpkg/available -List of available packages. -.TP -.I /var/lib/dpkg/status -Statuses of available packages. This file contains information about -wheter a package is marked for removing or not, wheter it is installed -or not, etc. See section -.B INFORMATION ABOUT PACKAGES -for more info. -.TP -.I control -See -.B deb(5) -for more information about this file. -.TP -.I conffiles -.B dpkg. -See -.B deb(5) -for more information about this file. -.TP -.I preinst -See -.B deb(5) -for more information about this file. -.TP -.I postinst -See -.B deb(5) -for more information about this file. -.TP -.I prerm -See -.B deb(5) -for more information about this file. -.TP -.I postrm -See -.B deb(5) -for more information about this file. - -.SH ENVIRONMENT VARIABLES -.TP -.B DPKG_NO_TSTP -Define this to something, if you prefer -.B dpkg -starting a new shell rather than suspending -.B dpkg, -while doing a shell escape. -.TP -.B SHELL -The program -.B dpkg -will execute while starting a new shell. - -.SH SEE ALSO -.B deb(5) -, -.B dpkg-deb(8) -, -.B dselect(8) -and -.B deb-control(5) - -.SH BUGS - -.B --no-act -usually gives less information that might be helpful. -.SH AUTHOR -.B dpkg -is written by Ian Jackson (ian@chiark.chu.cam.ac.uk). Manual page added -by Juho Vuori (javuori@cc.helsinki.fi). - - diff --git a/main/enquiry.c b/main/enquiry.c index c49e9a42..9483dad3 100644 --- a/main/enquiry.c +++ b/main/enquiry.c @@ -2,7 +2,7 @@ * dpkg - main program for package management * enquiry.c - status enquiry and listing options * - * Copyright (C) 1995 Ian Jackson + * Copyright (C) 1995,1996 Ian Jackson * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as @@ -73,11 +73,11 @@ Desired=Unknown/Install/Remove/Purge\n\ if (!pkg->installed.valid) blankpackageperfile(&pkg->installed); limiteddescription(pkg,44,&pdesc,&l); printf("%c%c%c %-15.15s %-14.14s %.*s\n", - "uirp"[pkg->want], + "uihrp"[pkg->want], "nUFiHc"[pkg->status], - " hRX"[pkg->eflag], + " R?#"[pkg->eflag], pkg->name, - versiondescribe(pkg->installed.version,pkg->installed.revision), + versiondescribe(&pkg->installed.version,vdew_never), l, pdesc); } @@ -431,19 +431,23 @@ void enqperpackage(const char *const *argv) { } void assertsupportpredepends(const char *const *argv) { + static struct versionrevision predepversion = {~0UL,0,0}; struct pkginfo *pkg; if (*argv) badusage("--assert-support-predepends does not take any arguments"); modstatdb_init(admindir,msdbrw_readonly); pkg= findpackage("dpkg"); - + if (!predepversion.epoch == ~0UL) { + predepversion.epoch= 0; + predepversion.version= nfstrsave("1.1.0"); + predepversion.revision= 0; + } switch (pkg->status) { case stat_installed: break; case stat_unpacked: case stat_halfconfigured: - if (versionsatisfied5(pkg->configversion,pkg->configrevision, - "1.1.0","", dvr_laterequal)) + if (versionsatisfied3(&pkg->configversion,&predepversion,dvr_laterequal)) break; printf("Version of dpkg with Pre-Depends support not yet configured.\n" " Please use `dpkg --configure dpkg', and then try again.\n"); diff --git a/main/errors.c b/main/errors.c index 797c8a84..495a16e5 100644 --- a/main/errors.c +++ b/main/errors.c @@ -86,7 +86,7 @@ int reportbroken_retexitstatus(void) { } int skip_due_to_hold(struct pkginfo *pkg) { - if (!(pkg->eflag & eflagf_hold)) return 0; + if (pkg->want != want_hold) return 0; if (fc_hold) { fprintf(stderr, "Package %s was on hold, processing it anyway as you request\n", pkg->name); diff --git a/main/help.c b/main/help.c index 48378a6c..edccc5d8 100644 --- a/main/help.c +++ b/main/help.c @@ -323,8 +323,8 @@ int maintainer_script_alternative(struct pkginfo *pkg, oldscriptpath= pkgadminfile(pkg,scriptname); arglist= buildarglist(scriptname, - ifok,versiondescribe(pkg->available.version, - pkg->available.revision), + ifok,versiondescribe(&pkg->available.version, + vdew_nonambig), (char*)0); sprintf(buf,"old %s script",description); if (stat(oldscriptpath,&stab)) { @@ -363,8 +363,8 @@ int maintainer_script_alternative(struct pkginfo *pkg, fprintf(stderr, DPKG " - trying script from the new package instead ...\n"); arglist= buildarglist(scriptname, - iffallback,versiondescribe(pkg->installed.version, - pkg->installed.revision), + iffallback,versiondescribe(&pkg->installed.version, + vdew_nonambig), (char*)0); strcpy(cidirrest,scriptname); sprintf(buf,"new %s script",description); diff --git a/main/main.c b/main/main.c index 22d866c4..6e08b973 100644 --- a/main/main.c +++ b/main/main.c @@ -41,12 +41,12 @@ #include "main.h" static void printversion(void) { - if (!fputs("Debian GNU/Linux `" DPKG "' package management program version " + if (!fputs("Debian Linux `" DPKG "' package management program version " DPKG_VERSION_ARCH ".\n" - "Copyright 1994,1995 Ian Jackson, Bruce Perens. This is free software;\n" + "Copyright 1994-1996 Ian Jackson, Bruce Perens. This is free software;\n" "see the GNU General Public Licence version 2 or later for copying\n" "conditions. There is NO warranty. See dpkg --licence for details.\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } static void usage(void) { @@ -74,7 +74,7 @@ Options: --help --version --licence --force-help -Dh|--debug=help\n\ --largemem|--smallmem --no-act\n\ \n\ Use `" DSELECT "' for user-friendly package management.\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } const char thisname[]= DPKG; @@ -209,7 +209,7 @@ DPKG " forcing options - control behaviour when problems found:\n\ auto-select [*] (De)select packages to install (remove) them\n\ dowgrade [*] Replace a package with a lower version\n\ configure-any Configure any package which may help this one\n\ - hold Process packages which are on hold\n\ + hold Process incidental packages even when on hold\n\ bad-path PATH is missing important programs, problems likely\n\ overwrite Overwrite a file from one package with another\n\ overwrite-diverted Overwrite a diverted file with an undiverted version\n\ @@ -264,6 +264,7 @@ static const struct cmdinfo cmdinfos[]= { { "yet-to-unpack", 0, 0, 0, 0, setaction, act_unpackchk }, { "assert-support-predepends", 0, 0, 0, 0, setaction, act_assuppredep }, { "print-architecture", 0, 0, 0, 0, setaction, act_printarch }, + { "print-installation-architecture", 0,0, 0,0, setaction, act_printinstarch }, { "predep-package", 0, 0, 0, 0, setaction, act_predeppackage }, { "pending", 'a', 0, &f_pending, 0, 0, 1 }, { "recursive", 'R', 0, &f_recursive, 0, 0, 1 }, @@ -364,6 +365,10 @@ int main(int argc, const char *const *argv) { case act_predeppackage: predeppackage(argv); break; + case act_printinstarch: + if (printf("%s\n",architecture) == EOF) werr("stdout"); + if (fflush(stdout)) werr("stdout"); + break; case act_printarch: printarchitecture(argv); break; diff --git a/main/main.h b/main/main.h index 21a1f9cf..e1919b70 100644 --- a/main/main.h +++ b/main/main.h @@ -51,7 +51,8 @@ struct packageinlist { enum action { act_unset, act_install, act_unpack, act_avail, act_configure, act_remove, act_purge, act_list, act_avreplace, act_avmerge, act_unpackchk, act_status, act_search, act_audit, act_listfiles, - act_assuppredep, act_printarch, act_predeppackage }; + act_assuppredep, act_printarch, act_predeppackage, + act_printinstarch }; enum conffopt { cfof_prompt = 001, @@ -184,14 +185,13 @@ void debug(int which, const char *fmt, ...) PRINTFFORMAT(2,3); int depisok(struct dependency *dep, struct varbuf *whynot, struct pkginfo **fixbyrm, int allowunconfigd); -const char *versiondescribe(const char *ver, const char *rev); struct cyclesofarlink; int findbreakcycle(struct pkginfo *pkg, struct cyclesofarlink *sofar); void describedepcon(struct varbuf *addto, struct dependency *dep); int versionsatisfied(struct pkginfoperfile *it, struct deppossi *against); -int versionsatisfied5(const char *itver, const char *itrev, - const char *refver, const char *refrev, +int versionsatisfied3(const struct versionrevision *it, + const struct versionrevision *ref, enum depverrel verrel); #endif /* MAIN_H */ diff --git a/main/packages.c b/main/packages.c index c4954712..91e78af5 100644 --- a/main/packages.c +++ b/main/packages.c @@ -172,8 +172,6 @@ void process_queue(void) { if (!pkg) continue; /* duplicate, which we removed earlier */ - if (skip_due_to_hold(pkg)) { pkg->clientdata->istobe= itb_normal; continue; } - assert(pkg->status <= stat_configfiles); if (setjmp(ejbuf)) { @@ -280,8 +278,8 @@ static int deppossi_ok_found(struct pkginfo *possdependee, varbufaddstr(oemsgs," Version of "); varbufaddstr(oemsgs,possdependee->name); varbufaddstr(oemsgs," on system is "); - varbufaddstr(oemsgs,versiondescribe(possdependee->installed.version, - possdependee->installed.revision)); + varbufaddstr(oemsgs,versiondescribe(&possdependee->installed.version, + vdew_nonambig)); varbufaddstr(oemsgs,".\n"); assert(checkversion->verrel != dvr_none); if (fc_depends) thisf= (dependtry >= 3) ? 2 : 1; @@ -297,7 +295,7 @@ static int deppossi_ok_found(struct pkginfo *possdependee, possdependee->clientdata->istobe == itb_installnew) { debug(dbg_depcondetail," unpacked/halfconfigured, defer"); return 1; - } else if (!removing && fc_configureany) { + } else if (!removing && fc_configureany && !skip_due_to_hold(possdependee)) { fprintf(stderr, DPKG ": also configuring `%s' (required by `%s')\n", possdependee->name, requiredby->name); diff --git a/main/processarc.c b/main/processarc.c index 4df46c31..7da90c02 100644 --- a/main/processarc.c +++ b/main/processarc.c @@ -82,7 +82,8 @@ void process_archive(const char *filename) { struct dirent *de; struct stat stab; struct packageinlist *deconpil, *deconpiltemp; - + enum versiondisplayepochwhen needepochs; + cleanup_pkg_failed= cleanup_conflictor_failed= 0; admindirlen= strlen(admindir); @@ -180,8 +181,6 @@ void process_archive(const char *filename) { "package architecture (%s) does not match system (%s)", pkg->available.architecture,architecture); - if (skip_due_to_hold(pkg)) { pop_cleanup(ehflag_normaltidy); return; } - if (!pkg->installed.valid) blankpackageperfile(&pkg->installed); assert(pkg->available.valid); @@ -205,27 +204,28 @@ void process_archive(const char *filename) { } if (pkg->status == stat_installed) { - r= versioncompare(pkg->available.version,pkg->available.revision, - pkg->installed.version,pkg->installed.revision); + r= versioncompare(&pkg->available.version,&pkg->installed.version); if (r < 0) { + needepochs= epochsdiffer(&pkg->available.version,&pkg->installed.version) ? + vdew_always : vdew_never; if (fc_downgrade) { fprintf(stderr, DPKG " - warning: downgrading %.250s from %.250s to %.250s.\n", pkg->name, - versiondescribe(pkg->installed.version,pkg->installed.revision), - versiondescribe(pkg->available.version,pkg->available.revision)); + versiondescribe(&pkg->installed.version,needepochs), + versiondescribe(&pkg->available.version,needepochs)); } else { fprintf(stderr, "Will not downgrade" " %.250s from version %.250s to %.250s, skipping.\n", pkg->name, - versiondescribe(pkg->installed.version,pkg->installed.revision), - versiondescribe(pkg->available.version,pkg->available.revision)); + versiondescribe(&pkg->installed.version,needepochs), + versiondescribe(&pkg->available.version,needepochs)); pop_cleanup(ehflag_normaltidy); return; } } else if (r == 0 && f_skipsame && /* same version fully installed ? */ pkg->status == stat_installed && !(pkg->eflag &= eflagf_reinstreq)) { fprintf(stderr, "Version %.250s of %.250s already installed, skipping.\n", - versiondescribe(pkg->installed.version,pkg->installed.revision), + versiondescribe(&pkg->installed.version,vdew_never), pkg->name); pop_cleanup(ehflag_normaltidy); return; @@ -400,11 +400,11 @@ void process_archive(const char *filename) { 3,(void*)deconpil->pkg,(void*)conflictor,(void*)pkg); maintainer_script_installed(deconpil->pkg, PRERMFILE, "pre-removal", "deconfigure", "in-favour", pkg->name, - versiondescribe(pkg->available.version, - pkg->available.revision), + versiondescribe(&pkg->available.version, + vdew_nonambig), "removing", conflictor->name, - versiondescribe(conflictor->installed.version, - conflictor->installed.revision), + versiondescribe(&conflictor->installed.version, + vdew_nonambig), (char*)0); } conflictor->status= stat_halfconfigured; @@ -413,8 +413,8 @@ void process_archive(const char *filename) { 2,(void*)conflictor,(void*)pkg); maintainer_script_installed(conflictor, PRERMFILE, "pre-removal", "remove", "in-favour", pkg->name, - versiondescribe(pkg->available.version, - pkg->available.revision), + versiondescribe(&pkg->available.version, + vdew_nonambig), (char*)0); conflictor->status= stat_halfinstalled; modstatdb_note(conflictor); @@ -432,15 +432,15 @@ void process_archive(const char *filename) { push_cleanup(cu_preinstnew,~ehflag_normaltidy, 0,0, 3,(void*)pkg,(void*)cidir,(void*)cidirrest); maintainer_script_new(PREINSTFILE, "pre-installation", cidir, cidirrest, - "install", versiondescribe(pkg->installed.version, - pkg->installed.revision), + "install", versiondescribe(&pkg->installed.version, + vdew_nonambig), (char*)0); } else { push_cleanup(cu_preinstupgrade,~ehflag_normaltidy, 0,0, 4,(void*)pkg,(void*)cidir,(void*)cidirrest,(void*)&oldversionstatus); maintainer_script_new(PREINSTFILE, "pre-installation", cidir, cidirrest, - "upgrade", versiondescribe(pkg->installed.version, - pkg->installed.revision), + "upgrade", versiondescribe(&pkg->installed.version, + vdew_nonambig), (char*)0); printf("Unpacking replacement %.250s ...\n",pkg->name); } @@ -715,10 +715,7 @@ void process_archive(const char *filename) { newpossi->ed= possi->ed; newpossi->next= 0; newpossi->nextrev= newpossi->backrev= 0; newpossi->verrel= possi->verrel; - if (possi->verrel != dvr_none) { - newpossi->version= possi->version; - newpossi->revision= possi->revision; - } + if (possi->verrel != dvr_none) newpossi->version= possi->version; newpossi->cyclebreak= 0; *newpossilastp= newpossi; newpossilastp= &newpossi->next; @@ -746,7 +743,6 @@ void process_archive(const char *filename) { pkg->installed.source= pkg->available.source; pkg->installed.architecture= 0; /* This is irrelevant in the status file. */ pkg->installed.version= pkg->available.version; - pkg->installed.revision= pkg->available.revision; /* We have to generate our own conffiles structure. */ pkg->installed.conffiles= 0; iconffileslastp= &pkg->installed.conffiles; @@ -844,8 +840,8 @@ void process_archive(const char *filename) { maintainer_script_installed(otherpkg, POSTRMFILE, "post-removal script (for disappearance)", "disappear", pkg->name, - versiondescribe(pkg->available.version, - pkg->available.revision), + versiondescribe(&pkg->available.version, + vdew_nonambig), (char*)0); /* OK, now we delete all the stuff in the `info' directory .. */ @@ -881,8 +877,8 @@ void process_archive(const char *filename) { otherpkg->installed.depends= 0; otherpkg->installed.essential= 0; - otherpkg->installed.description= otherpkg->installed.maintainer= - otherpkg->installed.version= otherpkg->installed.revision= 0; + otherpkg->installed.description= otherpkg->installed.maintainer= 0; + blankversion(&otherpkg->installed.version); otherpkg->installed.arbs= 0; otherpkg->clientdata->fileslistvalid= 0; diff --git a/main/remove.c b/main/remove.c index 87cfbecc..5f685f81 100644 --- a/main/remove.c +++ b/main/remove.c @@ -323,7 +323,7 @@ void removal_bulk(struct pkginfo *pkg) { /* We're about to remove the configuration, so remove the note * about which version it was ... */ - pkg->configversion= pkg->configrevision= 0; + blankversion(&pkg->configversion); modstatdb_note(pkg); /* Remove from our list any conffiles that aren't ours any more or @@ -455,8 +455,8 @@ void removal_bulk(struct pkginfo *pkg) { */ pkg->installed.depends= 0; pkg->installed.essential= 0; - pkg->installed.description= pkg->installed.maintainer= - pkg->installed.version= pkg->installed.revision= 0; + pkg->installed.description= pkg->installed.maintainer= 0; + blankversion(&pkg->installed.version); pkg->installed.arbs= 0; } diff --git a/methods/disk.setup b/methods/disk.setup index 5a692003..805e93ac 100644 --- a/methods/disk.setup +++ b/methods/disk.setup @@ -8,6 +8,8 @@ option=$3 cd "$vardir/methods/disk" tp=/tmp/ddm$$ +iarch=`dpkg --print-installation-architecture` + xit=1 trap ' rm -f $tp.? @@ -353,7 +355,7 @@ just answer \`none' and we'll go through the parts I need individually." defhierbase=none if [ -n "$p_hierbase" ] then - if [ -d "$mountpoint/$p_hierbase/stable/binary" ] + if [ -d "$mountpoint/$p_hierbase/stable/binary-i386" ] then echo " Last time you said \`$p_hierbase', and that looks plausible." @@ -364,7 +366,7 @@ Last time you said \`$p_hierbase', but that doesn't look plausible, since \`$p_hierbase/stable/binary' doesn't seem to exist." fi fi - if [ none = "$defhierbase" -a -d "$mountpoint/debian/stable/binary" ] + if [ none = "$defhierbase" -a -d "$mountpoint/debian/stable/binary-i386" ] then echo " \`/debian' exists and looks plausible, so that's the default." @@ -381,20 +383,20 @@ since \`$p_hierbase/stable/binary' doesn't seem to exist." then hierbase="" break - elif [ -d "$mountpoint/$response/stable/binary" ] + elif [ -d "$mountpoint/$response/stable/binary-i386" ] then hierbase="`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`" break fi echo \ -"$response/stable/binary does not exist. +"$response/stable/binary-i386 does not exist. " done whichmain=stable if [ -n "$hierbase" ] then - if [ -d "$mountpoint/$hierbase/development/binary" ] + if [ -d "$mountpoint/$hierbase/unstable/binary-$iarch" ] then echo \ ' @@ -438,7 +440,7 @@ find_area () { this_packages='' if [ -n "$hierbase" ] then - check_binary $1 "$hierbase/$3/binary" + check_binary $1 "$hierbase/$3/binary-$iarch" fi if [ $option = cdrom -a $2 = nf -a -z "$this_binary" ] then diff --git a/split/main.c b/split/main.c index 08645350..756dbf4e 100644 --- a/split/main.c +++ b/split/main.c @@ -34,12 +34,12 @@ static void printversion(void) { if (!fputs - ("Debian GNU/Linux `" SPLITTER "' package archive split/join tool;\n" - "version " DPKG_VERSION_ARCH - ". Copyright (C) 1994,1995 Ian Jackson. This is free\n" - "software; see the GNU General Public Licence version 2 or later for copying\n" - "conditions. There is NO warranty. See dpkg-split --licence for details.\n", - stderr)) werr("stderr"); + ("Debian Linux `" SPLITTER "' package split/join tool; " + "version " DPKG_VERSION_ARCH ".\n" + "Copyright (C) 1994-1996 Ian Jackson. This is free software; see the\n" + "GNU General Public Licence version 2 or later for copying conditions.\n" + "There is NO warranty. See dpkg-split --licence for details.\n", + stdout)) werr("stdout"); } static void usage(void) { @@ -60,7 +60,7 @@ Options: --depotdir (default is /var/lib/dpkg/parts)\n\ --msdos (generate 8.3 filenames)\n\ \n\ Exit status: 0 = OK; 1 = -a is not a part; 2 = trouble!\n", - stderr)) werr("stderr"); + stdout)) werr("stdout"); } const char thisname[]= SPLITTER; diff --git a/version.h b/version.h index f3d8a840..da0dfa2d 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define DPKG_VERSION "1.1.6" /* This line modified by Makefile */ +#define DPKG_VERSION "1.2.0" /* This line modified by Makefile */ -- 2.39.5