Browse Source

* Fixed some compiler warnings
* Make start-stop-daemon exit(1) when we don't find one of the
pid's we are trying to kill, in accordance with the man page.
* When running --configure on an already installed package, just
say it's installed, and not that it is in an unconfigurable
state
* Bah, add all the prefix/datadir... stuff back to the install
target in debian/rules (po/ doesn't use it)
* Add function to libdpkg that dpkg can call to make sure it's
compiled version matches that of the library. If it fails,
complain loudly, but allow to proceed
* Make dpkg check for uid 0 requirement, before checking the path
since not being root, is probably the reason that the PATH is
borked in the first place
* Make -p short for --print-avail, and -P short for --purge
* Fix typo in md5sum(1) man page
* start-stop-daemon: Add --background and --make-pidfile options
* update-alternatives: make sure we remove "old" symlinks when they
are no longer pertinent. Add /etc/alternatives/README that refers
to the update-alternatives(8) man page.
* dpkg-divert: Add check for being able to write to the old/new
destination before doing a rename. We fail on this, without
changing the diversion registry
* Fix bad regex in update-rc.d

Ben Collins 24 years ago
parent
commit
43d40df962

+ 27 - 0
ChangeLog

@@ -1,3 +1,30 @@
+Thu Oct 21 06:37:24 EDT 1999 Ben Collins <bcollins.debian.org>
+
+  * Fixed some compiler warnings
+  * Make start-stop-daemon exit(1) when we don't find one of the
+    pid's we are trying to kill, in accordance with the man page.
+  * When running --configure on an already installed package, just
+    say it's installed, and not that it is in an unconfigurable
+    state
+  * Bah, add all the prefix/datadir... stuff back to the install
+    target in debian/rules (po/ doesn't use it)
+  * Add function to libdpkg that dpkg can call to make sure it's
+    compiled version matches that of the library. If it fails,
+    complain loudly, but allow to proceed
+  * Make dpkg check for uid 0 requirement, before checking the path
+    since not being root, is probably the reason that the PATH is
+    borked in the first place
+  * Make -p short for --print-avail, and -P short for --purge
+  * Fix typo in md5sum(1) man page
+  * start-stop-daemon: Add --background and --make-pidfile options
+  * update-alternatives: make sure we remove "old" symlinks when they
+    are no longer pertinent. Add /etc/alternatives/README that refers
+    to the update-alternatives(8) man page.
+  * dpkg-divert: Add check for being able to write to the old/new
+    destination before doing a rename. We fail on this, without
+    changing the diversion registry
+  * Fix bad regex in update-rc.d
+
 Tue Oct 19 18:07:28 EDT 1999 Ben Collins <bcollins.debian.org>
 
   * Ok, TMPDIR usage is back in dpkg-deb and working

+ 22 - 3
debian/changelog

@@ -31,9 +31,6 @@ dpkg (1.4.1.17) unstable; urgency=low
     already generated anyway
   * Removed the ltconfig patch, and resort to a debian/rules fix
     to libtool itself after running configure
-  * Use DESTDIR when installing instead of specifying all our
-    dest dirs seperately in the make line. Also fix some of the
-    make files to use DESTDIR when installing files
   * Removed shlibs.default.i386. It's now a template for arch porting to
     Debian/dpkg, we install it still, if there exists a file matching the
     arch
@@ -48,6 +45,28 @@ dpkg (1.4.1.17) unstable; urgency=low
     distclean and all that other stuff. Don't run "make dist", we
     simply copy the .tar.gz that dpkg-source creates for the byhand
     source.
+  * Make start-stop-daemon exit(1) when we don't find one of the
+    pid's we are trying to kill, in accordance with the man page.
+  * When running --configure on an already installed package, just
+    say it's installed, and not that it is in an unconfigurable
+    state
+  * Fixed some compiler warnings
+  * Add function to libdpkg that dpkg can call to make sure it's
+    compiled version matches that of the library. If it fails,
+    complain loudly, but allow to proceed
+  * Make dpkg check for uid 0 requirement, before checking the path
+    since not being root, is probably the reason that the PATH is
+    borked in the first place
+  * Make -p short for --print-avail, and -P short for --purge
+  * Fix typo in md5sum(1) man page
+  * start-stop-daemon: Add --background and --make-pidfile options
+  * update-alternatives: make sure we remove "old" symlinks when they
+    are no longer pertinent. Add /etc/alternatives/README that refers
+    to the update-alternatives(8) man page.
+  * dpkg-divert: Add check for being able to write to the old/new
+    destination before doing a rename. We fail on this, without
+    changing the diversion registry
+  * Fix bad regex in update-rc.d
 
  -- Wichert Akkerman <wakkerma@debian.org>  UNRELEASED
 

+ 10 - 1
debian/rules

@@ -62,7 +62,16 @@ binary-trees: build
 		debian/tmp-dev/etc/dpkg/shlibs.default ; \
 	fi
 	cp debian/{prerm,postinst} $(mcidir)/.
-	$(MAKE) -C $(BUILD) DESTDIR=$(DIR)/debian/tmp-main install
+	
+	$(MAKE) -C $(BUILD) install \
+		prefix=$(DIR)/debian/tmp-main/usr \
+		sysconfdir=$(DIR)/debian/tmp-main/etc \
+		sharedstatedir=$(DIR)/debian/tmp-main/var/lib \
+		localstatedir=$(DIR)/debian/tmp-main/var/lib \
+		datadir=$(DIR)/debian/tmp-main/usr/share \
+		mandir=$(DIR)/debian/tmp-main/usr/share/man \
+		infodir=$(DIR)/debian/tmp-main/usr/share/info
+	
 	install -m 755 debian/dev-postinst debian/tmp-dev/DEBIAN/postinst
 	install -m 755 debian/dev-prerm debian/tmp-dev/DEBIAN/prerm
 	install -d debian/tmp-dev/etc/emacs/site-start.d

+ 1 - 1
dpkg-deb/build.c

@@ -72,7 +72,7 @@ void do_build(const char *const *argv) {
   directory= *argv++; if (!directory) badusage(_("--build needs a directory argument"));
   /* template for our tempfiles */
   if ((envbuf= getenv("TMPDIR")) == NULL)
-    envbuf= P_tmpdir;
+    envbuf= (char *)P_tmpdir;
   tfbuf = (char *)malloc(strlen(envbuf)+13);
   strcpy(tfbuf,envbuf);
   strcat(tfbuf,"/dpkg.XXXXXX");

+ 2 - 0
dselect/pkgdepcon.cc

@@ -333,6 +333,8 @@ int packagelist::resolvedepcon(dependency *depends) {
   default:
     internerr("unknown deptype");
   }
+  /* never reached, make gcc happy */
+  return 1;
 }
 
 int packagelist::deppossatisfied(deppossi *possi, perpackagestate **fixbyupgrade) {

+ 2 - 0
dselect/pkglist.cc

@@ -78,6 +78,8 @@ int packagelist::compareentries(struct perpackagestate *a,
   default:
     internerr("unsorted or unknown in compareentries");
   }
+  /* never reached, make gcc happy */
+  return 1;
 }
 
 void packagelist::discardheadings() {

+ 1 - 0
include/dpkg.h.in

@@ -202,5 +202,6 @@ extern volatile int onerr_abort;
 
 struct cmdinfo;
 void showcopyright(const struct cmdinfo*, const char*);
+char *libdpkgver(void);
 
 #endif /* DPKG_H */

+ 2 - 0
lib/dump.c

@@ -27,6 +27,8 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <config.h>
 #include <dpkg.h>

+ 1 - 1
lib/parse.c

@@ -200,7 +200,7 @@ int parsedb(const char *filename, enum parsedbflags flags,
                      &newpifp->maintainer, "maintainer");
       if (newpig.status != stat_halfinstalled)
         parsemustfield(file,filename,lno, warnto,warncount,&newpig,0,
-                       &newpifp->version.version, "version");
+                       (char **)&newpifp->version.version, "version");
     }
     if (flags & pdb_recordavailable)
       parsemustfield(file,filename,lno, warnto,warncount,&newpig,1,

+ 5 - 0
lib/showcright.c

@@ -24,6 +24,7 @@
 
 #include <config.h>
 #include <dpkg.h>
+#include <version.h>
 
 void showcopyright(const struct cmdinfo *c, const char *v) {
   int fd;
@@ -33,3 +34,7 @@ void showcopyright(const struct cmdinfo *c, const char *v) {
   execlp(CAT,CAT,"-",(char*)0);
   ohshite(_("unable to exec cat for displaying GPL file"));
 }
+
+char *libdpkgver(void) {
+  return DPKG_VERSION;
+}

+ 6 - 6
main/archives.c

@@ -698,6 +698,12 @@ void archivefiles(const char *const *argv) {
   const char **arglist;
   char *p;
 
+  modstatdb_init(admindir,
+                 f_noact ?                     msdbrw_readonly
+               : cipaction->arg == act_avail ? msdbrw_write
+               : fc_nonroot ?                  msdbrw_write
+               :                               msdbrw_needsuperuser);
+
   checkpath();
   
   if (f_recursive) {
@@ -770,12 +776,6 @@ void archivefiles(const char *const *argv) {
     
   }
 
-  modstatdb_init(admindir,
-                 f_noact ?                     msdbrw_readonly
-               : cipaction->arg == act_avail ? msdbrw_write
-               : fc_nonroot ?                  msdbrw_write
-               :                               msdbrw_needsuperuser);
-
   currenttime= time(0);
 
   varbufaddstr(&fnamevb,instdir); varbufaddc(&fnamevb,'/');

+ 2 - 0
main/configure.c

@@ -78,6 +78,8 @@ void deferred_configure(struct pkginfo *pkg) {
   
   if (pkg->status == stat_notinstalled)
     ohshit(_("no package named `%s' is installed, cannot configure"),pkg->name);
+  if (pkg->status == stat_installed)
+    ohshit(_("package %.250s is already installed and configured"), pkg->name);
   if (pkg->status != stat_unpacked && pkg->status != stat_halfconfigured)
     ohshit(_("package %.250s is not ready for configuration\n"
            " cannot configure (current status `%.250s')"),

+ 3 - 3
main/dpkg.8

@@ -147,12 +147,12 @@ something goes wrong.
 
 \fB2.\fP Run \fIpostinst\fP script, if provided by the package.
 .TP
-\fBdpkg -r\fP | \fB--remove\fP | \fB --purge \fP\fIpackage\fP ... | \fB-a\fP | \fB--pending\fP
+\fBdpkg -r\fP | \fB--remove\fP | \fB-P\fP | \fB--purge \fP\fIpackage\fP ... | \fB-a\fP | \fB--pending\fP
 Remove an installed package.  \fB-r\fP or \fB--remove\fP remove
 everything except configuration files.  This may avoid having to
 reconfigure the package if it is reinstalled later.  (Configuration
 files are the files listed in the \fIdebian/conffiles\fP control
-file).  \fB--purge\fP removes everything, including configuration
+file).  \fB-P\fP or \fB--purge\fP removes everything, including configuration
 files.  If \fB-a\fP or \fB--pending\fP is given instead of a package
 name, then all packages unpacked, but marked to be removed or purged
 in file \fI/var/lib/dpkg/status\fP, are removed or purged,
@@ -170,7 +170,7 @@ Removing of a package consists of the following steps:
 \fB3.\fP Run \fIpostrm\fP script
 .br
 .TP
-.BI "dpkg  --print-avail " package
+.BI "dpkg  -p|--print-avail " package
 Display details about \fIpackage\fP, as found in
 \fI/var/lib/dpkg/available\fP.
 .TP

+ 2 - 2
main/enquiry.c

@@ -467,7 +467,7 @@ void enqperpackage(const char *const *argv) {
   }
 }
 
-void assertversion(const char *const *argv,
+static void assertversion(const char *const *argv,
 			struct versionrevision *verrev_buf,
 			const char *reqversion) {
   struct pkginfo *pkg;
@@ -520,7 +520,7 @@ void predeppackage(const char *const *argv) {
   static struct varbuf vb;
   
   struct pkgiterator *it;
-  struct pkginfo *pkg, *startpkg, *trypkg;
+  struct pkginfo *pkg= 0, *startpkg, *trypkg;
   struct dependency *dep;
   struct deppossi *possi, *provider;
 

+ 22 - 0
main/help.c

@@ -31,6 +31,7 @@
 
 #include <config.h>
 #include <dpkg.h>
+#include <version.h>
 #include <dpkg-db.h>
 
 #include "filesdb.h"
@@ -504,3 +505,24 @@ void ensure_pathname_nonexisting(const char *pathname) {
   debug(dbg_eachfile,"ensure_pathname_nonexisting running rm -rf");
   waitsubproc(c1,"rm cleanup",0);
 }
+
+void check_libver (void) {
+  int c;
+  if (!strcmp(DPKG_VERSION, libdpkgver())) return;
+  /* ooh, we have a version mismatch with the library,
+   * continue, but warn LOUDLY about possible problems.
+   */
+  fprintf(stderr, _("\
+WARNING: A mismatch between dpkg and libdpkg.so has\n\
+been detected. Somehow, your system has a different\n\
+version of dpkg than the library that is uses. This\n\
+may not cause any problems, but it does reflect a\n\
+serious condition. You should really reinstall the dpkg\n\
+package before continuing.\n\
+\n\
+Press 'Q' to exit, any other key to continue: "));
+  c= getc(stdin);
+  if (c == 'q' || c == 'Q')
+    ohshite(_("Quitting at user request"));
+  return;
+}

+ 27 - 25
main/main.c

@@ -59,28 +59,28 @@ Usage: \n\
   dpkg -i|--install      <.deb file name> ... | -R|--recursive <dir> ...\n\
   dpkg --unpack          <.deb file name> ... | -R|--recursive <dir> ...\n\
   dpkg -A|--record-avail <.deb file name> ... | -R|--recursive <dir> ...\n\
-  dpkg --configure           <package name> ... | -a|--pending\n\
-  dpkg -r|--remove | --purge <package name> ... | -a|--pending\n\
-  dpkg --get-selections [<pattern> ...]   get list of selections to stdout\n\
-  dpkg --set-selections                   set package selections from stdin\n\
-  dpkg --update-avail <Packages-file>     replace available packages info\n\
-  dpkg --merge-avail <Packages-file>      merge with info from file\n\
-  dpkg --clear-avail                      erase existing available info\n\
-  dpkg --forget-old-unavail               forget uninstalled unavailable pkgs\n\
-  dpkg -s|--status <package-name> ...     display package status details\n\
-  dpkg --print-avail <package-name> ...   display available version details\n\
-  dpkg -L|--listfiles <package-name> ...  list files `owned' by package(s)\n\
-  dpkg -l|--list [<pattern> ...]          list packages concisely\n\
-  dpkg -S|--search <pattern> ...          find package(s) owning file(s)\n\
-  dpkg -C|--audit                         check for broken package(s)\n\
-  dpkg --abort-after <n>                  abort after encountering <n> errors\n\
-  dpkg --print-architecture               print target architecture (uses GCC)\n\
-  dpkg --print-gnu-build-architecture     print GNU version of target arch\n\
-  dpkg --print-installation-architecture  print host architecture (for inst'n)\n\
-  dpkg --compare-versions <a> <rel> <b>   compare version numbers - see below\n\
-  dpkg --help | --version                 show this help / version number\n\
-  dpkg --force-help | -Dh|--debug=help    help on forcing resp. debugging\n\
-  dpkg --licence                          print copyright licencing terms\n\
+  dpkg --configure              <package name> ... | -a|--pending\n\
+  dpkg -r|--remove | -P|--purge <package name> ... | -a|--pending\n\
+  dpkg --get-selections [<pattern> ...]    get list of selections to stdout\n\
+  dpkg --set-selections                    set package selections from stdin\n\
+  dpkg --update-avail <Packages-file>      replace available packages info\n\
+  dpkg --merge-avail <Packages-file>       merge with info from file\n\
+  dpkg --clear-avail                       erase existing available info\n\
+  dpkg --forget-old-unavail                forget uninstalled unavailable pkgs\n\
+  dpkg -s|--status <package-name> ...      display package status details\n\
+  dpkg -p|--print-avail <package-name> ... display available version details\n\
+  dpkg -L|--listfiles <package-name> ...   list files `owned' by package(s)\n\
+  dpkg -l|--list [<pattern> ...]           list packages concisely\n\
+  dpkg -S|--search <pattern> ...           find package(s) owning file(s)\n\
+  dpkg -C|--audit                          check for broken package(s)\n\
+  dpkg --abort-after <n>                   abort after encountering <n> errors\n\
+  dpkg --print-architecture                print target architecture (uses GCC)\n\
+  dpkg --print-gnu-build-architecture      print GNU version of target arch\n\
+  dpkg --print-installation-architecture   print host architecture (for inst'n)\n\
+  dpkg --compare-versions <a> <rel> <b>    compare version numbers - see below\n\
+  dpkg --help | --version                  show this help / version number\n\
+  dpkg --force-help | -Dh|--debug=help     help on forcing resp. debugging\n\
+  dpkg --licence                           print copyright licencing terms\n\
 \n\
 Use dpkg -b|--build|-c|--contents|-e|--control|-I|--info|-f|--field|\n\
  -x|--extract|-X|--vextract|--fsys-tarfile  on archives (type %s --help.)\n\
@@ -325,12 +325,12 @@ static const struct cmdinfo cmdinfos[]= {
   ACTION( "record-avail",                   'A', act_avail,         archivefiles    ),
   ACTION( "configure",                       0,  act_configure,     packages        ),
   ACTION( "remove",                         'r', act_remove,        packages        ),
-  ACTION( "purge",                           0,  act_purge,         packages        ),
+  ACTION( "purge",                          'P', act_purge,         packages        ),
   ACTION( "listfiles",                      'L', act_listfiles,     enqperpackage   ),
   ACTION( "status",                         's', act_status,        enqperpackage   ),
   ACTION( "get-selections",                  0,  act_getselections, getselections   ),
   ACTION( "set-selections",                  0,  act_setselections, setselections   ),
-  ACTION( "print-avail",                     0,  act_printavail,    enqperpackage   ),
+  ACTION( "print-avail",                    'p', act_printavail,    enqperpackage   ),
   ACTION( "update-avail",                    0,  act_avreplace,     updateavailable ),
   ACTION( "merge-avail",                     0,  act_avmerge,       updateavailable ),
   ACTION( "clear-avail",                     0,  act_avclear,       updateavailable ),
@@ -394,7 +394,9 @@ int main(int argc, const char *const *argv) {
   push_error_handler(&ejbuf,print_error_fatal,0);
 
   umask(022); /* Make sure all our status databases are readable. */
-  
+ 
+  check_libver();
+
   for (argvs=argv+1; (argp= *argvs) && *argp++=='-'; argvs++) {
     if (*argp++=='-') {
       if (!strcmp(argp,"-")) break;

+ 1 - 0
main/main.h

@@ -203,6 +203,7 @@ enum debugflags {
 };
   
 void debug(int which, const char *fmt, ...) PRINTFFORMAT(2,3);
+void check_libver(void);
 
 /* from depcon.c */
 

+ 1 - 1
main/packages.c

@@ -67,11 +67,11 @@ void packages(const char *const *argv) {
   const char *thisarg;
   int l;
   
-  checkpath();
   modstatdb_init(admindir,
                  f_noact ?    msdbrw_readonly
                : fc_nonroot ? msdbrw_write
                :              msdbrw_needsuperuser);
+  checkpath();
 
   if (f_pending) {
 

+ 1 - 1
md5sum/md5sum.1

@@ -65,7 +65,7 @@ with other manpages.
 
 .B md5sum
 does not accept standard options like
-.BR -\-\help .
+.BR --help .
 
 .SH AUTHOR
 

+ 1 - 1
md5sum/md5sum.c

@@ -66,7 +66,7 @@ char *progname;
 int verbose = 0;
 int bin_mode = 0;
 
-void
+int
 main(int argc, char **argv)
 {
 	int opt, rc = 0;

+ 2 - 1
scripts/Makefile.am

@@ -43,7 +43,7 @@ EXTRA_DIST		= update-rc.d.pl \
 			  update-alternatives.pl install-info.pl dpkg-divert.pl \
 			  cleanup-info.pl controllib.pl debian-changelog-mode.el \
 			  cl-debian.pl dpkg-architecture.pl dpkg-scansources.pl \
-			  $(man_MANS)
+			  $(man_MANS) README.alternatives
 
 noinst_DATA		= cl-debian
 
@@ -78,6 +78,7 @@ dpkg-scansources.8: dpkg-scansources.pl
 
 install-data-local: cl-debian
 	$(mkinstalldirs) $(DESTDIR)$(altslocalstatedir) $(DESTDIR)$(altssysconfdir)
+	$(INSTALL_DATA) $(srcdir)/README.alternatives $(DESTDIR)$(altssysconfdir)/README
 	set -e; for f in $(LSMANL); do ln -sf $(mandir)/man1/dpkg-source.1 $(DESTDIR)$(mandir)/man1/$$f.1; done
 	$(mkinstalldirs) $(DESTDIR)$(parsechangelogdir)
 	$(INSTALL_PROGRAM) cl-debian $(DESTDIR)$(parsechangelogdir)/debian

+ 2 - 0
scripts/README.alternatives

@@ -0,0 +1,2 @@
+Please read the update-alternatives(8) man page for information on this
+directory and its contents.

+ 10 - 0
scripts/dpkg-divert.pl

@@ -176,10 +176,20 @@ sub infol {
 sub checkrename {
     return unless $dorename;
     ($rsrc,$rdest) = @_;
+    my %exist;
     (@ssrc= lstat($rsrc)) || $! == &ENOENT ||
         &quit("cannot stat old name \`$rsrc': $!");
+    $exist{$rsrc} = 1 unless $! != &ENOENT;
     (@sdest= lstat($rdest)) || $! == &ENOENT ||
         &quit("cannot stat new name \`$rdest': $!");
+    $exist{$rdest} = 1 unless $! != &ENOENT;
+    foreach $file ($rsrc,$rdest) {
+	open (TMP, "a $file") || &quit("error checking \`$file': $!");
+	close TMP;
+	if ($exist{$file} == 1) {
+	    unlink ("$file");
+	}
+    }
     if (@ssrc && @sdest &&
         !($ssrc[0] == $sdest[0] && $ssrc[1] == $sdest[1])) {
         &quit("rename involves overwriting \`$rdest' with\n".

+ 2 - 0
scripts/update-alternatives.pl

@@ -406,6 +406,8 @@ if ($manual eq 'auto') {
             &pr("Removing $sname ($slink), not appropriate with $best.");
             unlink("$altdir/$sname") || $! == &ENOENT ||
                 &quit("unable to remove $altdir/$sname: $!");
+	    unlink("$slink") || $! == &ENOENT ||
+	        &quit("unable to remove $slink: $!");
         } else {
             if (defined($linkname= readlink("$altdir/$sname")) && $linkname eq $spath) {
                 &pr("Leaving $sname ($slink) pointing to $spath.");

+ 4 - 4
scripts/update-rc.d.pl

@@ -52,10 +52,10 @@ if ($ARGV[0] ne 'remove') {
 }
 
 $_ = $ARGV[0];
-if    (/^remove$/)     { &checklinks ("remove"); }
-elsif (/^defaults$/)   { &defaults; &makelinks }
-elsif (/^start|stop$/) { &startstop; &makelinks; }
-else                   { &usage; }
+if    (/^remove$/)       { &checklinks ("remove"); }
+elsif (/^defaults$/)     { &defaults; &makelinks }
+elsif (/^(start|stop)$/) { &startstop; &makelinks; }
+else                     { &usage; }
 
 exit (0);
 

+ 22 - 0
utils/start-stop-daemon.8

@@ -124,6 +124,28 @@ Do not print informational messages; only display error messages.
 .I -c|--chuid
 Change to this username/uid before starting the process
 .TP
+.I -b|--background
+Typically used with programs that don't detach on their own. This option
+will force
+.B start-stop-daemon
+to fork before starting the process, and force it into the background.
+.B WARNING:
+start-stop-daemon
+cannot check the exit status if the process fails to execute for
+.B any
+reason. This is a last resort, and is only meant for programs that either
+make no sense forking on their own, or where it's not feasible to add the
+code for it to do this itself.
+.TP
+.I -m|--make-pidfile
+Used when starting a program that does not create its own pid file. This
+option will make
+.B start-stop-daemon
+create the file referenced with
+.B --pidfile
+and place the pid into it just before executing the process. Note, it will
+not be removed when stopping the program.
+.TP
 .I -v|--verbose
 Print verbose informational messages.
 .TP

+ 95 - 22
utils/start-stop-daemon.c

@@ -9,7 +9,11 @@
  * <schwarz@monet.m.isar.de>, to make output conform to the Debian
  * Console Message Standard, also placed in public domain.  Minor
  * changes by Klee Dienes <klee@debian.org>, also placed in the Public
- * Domain. */
+ * Domain.
+ *
+ * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
+ * and --make-pidfile options, placed in public domain aswell.
+ */
 
 #include "config.h"
 #define _GNU_SOURCE
@@ -40,6 +44,9 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <pwd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fcntl.h>
 
 #ifdef HAVE_ERROR_H
 #include <error.h>
@@ -53,6 +60,8 @@ static int quietmode = 0;
 static int exitnodo = 1;
 static int start = 0;
 static int stop = 0;
+static int background = 0;
+static int mpidfile = 0;
 static int signal_nr = 15;
 static const char *signal_str = NULL;
 static int user_id = -1;
@@ -88,7 +97,7 @@ static int pid_is_user(int pid, int uid);
 static int pid_is_cmd(int pid, const char *name);
 static void check(int pid);
 static void do_pidfile(const char *name);
-static void do_stop(void);
+static int do_stop(void);
 #if defined(OSLinux)
 static int pid_is_exec(int pid, const struct stat *esb);
 #endif
@@ -165,6 +174,8 @@ Options (at least one of --exec|--pidfile|--user is required):
   -n|--name <process-name>      stop processes with this name\n\
   -s|--signal <signal>          signal to send (default TERM)\n\
   -a|--startas <pathname>       program to start (default is <executable>)\n\
+  -b|--background               force the process to detach\n\
+  -m|--make-pidfile             create the pidfile before starting\n\
   -t|--test                     test mode, don't do anything\n\
   -o|--oknodo                   exit status 0 (not 1) if nothing done\n\
   -q|--quiet                    be more quiet\n\
@@ -226,27 +237,29 @@ static void
 parse_options(int argc, char * const *argv)
 {
 	static struct option longopts[] = {
-		{ "help",	0, NULL, 'H'},
-		{ "stop",	0, NULL, 'K'},
-		{ "start",	0, NULL, 'S'},
-		{ "version",	0, NULL, 'V'},
-		{ "startas",	1, NULL, 'a'},
-		{ "name",	1, NULL, 'n'},
-		{ "oknodo",	0, NULL, 'o'},
-		{ "pidfile",	1, NULL, 'p'},
-		{ "quiet",	0, NULL, 'q'},
-		{ "signal",	1, NULL, 's'},
-		{ "test",	0, NULL, 't'},
-		{ "user",	1, NULL, 'u'},
-		{ "verbose",	0, NULL, 'v'},
-		{ "exec",	1, NULL, 'x'},
-		{ "chuid",	1, NULL, 'c'},
+		{ "help",	  0, NULL, 'H'},
+		{ "stop",	  0, NULL, 'K'},
+		{ "start",	  0, NULL, 'S'},
+		{ "version",	  0, NULL, 'V'},
+		{ "startas",	  1, NULL, 'a'},
+		{ "name",	  1, NULL, 'n'},
+		{ "oknodo",	  0, NULL, 'o'},
+		{ "pidfile",	  1, NULL, 'p'},
+		{ "quiet",	  0, NULL, 'q'},
+		{ "signal",	  1, NULL, 's'},
+		{ "test",	  0, NULL, 't'},
+		{ "user",	  1, NULL, 'u'},
+		{ "verbose",	  0, NULL, 'v'},
+		{ "exec",	  1, NULL, 'x'},
+		{ "chuid",	  1, NULL, 'c'},
+		{ "background",   0, NULL, 'b'},
+		{ "make-pidfile", 0, NULL, 'm'},
 		{ NULL,		0, NULL, 0}
 	};
 	int c;
 
 	for (;;) {
-		c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:c:",
+		c = getopt_long(argc, argv, "HKSVa:n:op:qs:tu:vx:c:bm",
 				longopts, (int *) 0);
 		if (c == -1)
 			break;
@@ -296,6 +309,12 @@ parse_options(int argc, char * const *argv)
 		case 'c':  /* --chuid <username>|<uid> */
 			changeuser = optarg;
 			break;
+		case 'b':  /* --background */
+			background = 1;
+			break;
+		case 'm':  /* --make-pidfile */
+			mpidfile = 1;
+			break;
 		default:
 			badusage(NULL);  /* message printed by getopt */
 		}
@@ -320,6 +339,13 @@ parse_options(int argc, char * const *argv)
 
 	if (start && !startas)
 		badusage("--start needs --exec or --startas");
+
+	if (mpidfile && pidfile == NULL)
+		badusage("--make-pidfile is only relevant with --pidfile");
+
+	if (background && !start)
+		badusage("--background is only relevant with --start");
+
 }
 
 #if defined(OSLinux)
@@ -497,12 +523,13 @@ do_psinit(void)
 }
 #endif /* OSHURD */
 
-
-static void
+/* return 1 on failure */
+static int
 do_stop(void)
 {
 	char what[1024];
 	struct pid_list *p;
+	int retval = 0;
 
 	if (cmdname)
 		strcpy(what, cmdname);
@@ -526,9 +553,11 @@ do_stop(void)
 			       signal_nr, p->pid);
 		else if (kill(p->pid, signal_nr) == 0)
 			push(&killed, p->pid);
-		else
+		else {
 			printf("%s: warning: failed to kill %d: %s\n",
 			       progname, p->pid, strerror(errno));
+			retval += 1;
+		}
 	}
 	if (quietmode < 0 && killed) {
 		printf("Stopped %s (pid", what);
@@ -536,6 +565,7 @@ do_stop(void)
 			printf(" %d", p->pid);
 		printf(").\n");
 	}
+	return retval;
 }
 
 
@@ -577,7 +607,12 @@ main(int argc, char **argv)
 		do_procinit();
 
 	if (stop) {
-		do_stop();
+		int i = do_stop();
+		if (i) {
+			if (quietmode <= 0)
+				printf("%d pids were not killed\n", i);
+			exit(1);
+		}
 		exit(0);
 	}
 
@@ -590,6 +625,8 @@ main(int argc, char **argv)
 		printf("Would start %s ", startas);
 		while (argc-- > 0)
 			printf("%s ", *argv++);
+		if (changeuser != NULL)
+			printf(" (as user %s[%d])", changeuser, runas_id);
 		printf(".\n");
 		exit(0);
 	}
@@ -598,6 +635,42 @@ main(int argc, char **argv)
 	*--argv = startas;
 	if (changeuser != NULL && seteuid(runas_id))
 		fatal("Unable to set effective uid to %s", changeuser);
+	if (background) { /* ok, we need to detach this process */
+		int i, fd;
+		if (quietmode < 0)
+			printf("Detatching to start %s...", startas);
+		i = fork();
+		if (i<0) {
+			fatal("Unable to fork.\n");
+		}
+		if (i) { /* parent */
+			if (quietmode < 0)
+				printf("done.\n");
+			exit(0);
+		}
+		 /* child continues here */
+		 /* now close all extra fds */
+		for (i=getdtablesize()-1; i>=0; --i) close(i);
+		 /* change tty */
+		fd = open("/dev/tty", O_RDWR);
+		ioctl(fd, TIOCNOTTY, 0);
+		close(fd);
+		chdir("/");
+		umask(022); /* set a default for dumb programs */
+		setpgrp();  /* set the process group */
+		fd=open("/dev/null", O_RDWR); /* stdin */
+		dup(fd); /* stdout */
+		dup(fd); /* stderr */
+	}
+	if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */
+		FILE *pidf = fopen(pidfile, "w");
+		pid_t pidt = getpid();
+		if (pidf == NULL)
+			fatal("Unable to open pidfile `%s' for writing: %s", pidfile,
+				strerror(errno));
+		fprintf(pidf, "%d\n", pidt);
+		fclose(pidf);
+	}
 	execv(startas, argv);
 	fatal("Unable to start %s: %s", startas, strerror(errno));
 }