From 0683223aa93d14e4b1d0620010392c518a3a6392 Mon Sep 17 00:00:00 2001 Message-Id: <0683223aa93d14e4b1d0620010392c518a3a6392.1714920420.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sat, 6 Jan 2007 12:49:56 +0000 Subject: [PATCH] daemonize, versioncmp: Generally useful functions from tripe. Organization: Straylight/Edgeware From: Mark Wooding See the manual for descriptions. --- Makefile.am | 2 + daemonize.c | 88 ++++++++++++++++++++++ daemonize.h | 68 +++++++++++++++++ man/Makefile.am | 10 +-- man/daemonize.3 | 41 ++++++++++ man/versioncmp.3 | 56 ++++++++++++++ versioncmp.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++ versioncmp.h | 78 +++++++++++++++++++ 8 files changed, 530 insertions(+), 5 deletions(-) create mode 100644 daemonize.c create mode 100644 daemonize.h create mode 100644 man/daemonize.3 create mode 100644 man/versioncmp.3 create mode 100644 versioncmp.c create mode 100644 versioncmp.h diff --git a/Makefile.am b/Makefile.am index 4437953..5feca10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,6 +48,7 @@ pkginclude_HEADERS = \ trace.h track.h unihash.h \ pool.h \ atom.h assoc.h darray.h dstr.h dspool.h hash.h sym.h crc32.h \ + daemonize.h versioncmp.h \ env.h fdflags.h fdpass.h fwatch.h lock.h \ bres.h conn.h lbuf.h ident.h pkbuf.h sel.h selbuf.h selpk.h sig.h \ tv.h \ @@ -67,6 +68,7 @@ libmLib_la_SOURCES = \ sym.c \ crc32.c crc32-tab.c \ unihash.c unihash-global.c \ + daemonize.c versioncmp.c \ env.c fdflags.c fdpass.c fwatch.c lock.c \ @BRES_SOURCE@.c \ conn.c lbuf.c ident.c pkbuf.c sel.c selbuf.c selpk.c sig.c \ diff --git a/daemonize.c b/daemonize.c new file mode 100644 index 0000000..f549ae2 --- /dev/null +++ b/daemonize.c @@ -0,0 +1,88 @@ +/* -*-c-*- + * + * $Id$ + * + * Become a daemon, detaching from terminals + * + * (c) 2007 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include + +#include "daemonize.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @detachtty@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Detaches from the current terminal and ensures it can never + * acquire a new one. Calls @fork@. + */ + +void detachtty(void) +{ +#ifdef TIOCNOTTY + { + int fd; + if ((fd = open("/dev/tty", O_RDONLY)) >= 0) { + ioctl(fd, TIOCNOTTY); + close(fd); + } + } +#endif + setsid(); + if (fork() > 0) + _exit(0); +} + +/* --- @daemonize@ --- * + * + * Arguments: --- + * + * Returns: Zero if OK, nonzero on failure. + * + * Use: Becomes a daemon. + */ + +int daemonize(void) +{ + pid_t kid; + + if ((kid = fork()) < 0) + return (-1); + if (kid) + _exit(0); + detachtty(); + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/daemonize.h b/daemonize.h new file mode 100644 index 0000000..7ab8a83 --- /dev/null +++ b/daemonize.h @@ -0,0 +1,68 @@ +/* -*-c-*- + * + * $Id$ + * + * Become a daemon, detaching from terminals + * + * (c) 2007 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef MLIB_DAEMONIZE_H +#define MLIB_DAEMONIZE_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Functions provided ------------------------------------------------*/ + +/* --- @detachtty@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Detaches from the current terminal and ensures it can never + * acquire a new one. Calls @fork@. + */ + +extern void detachtty(void); + +/* --- @daemonize@ --- * + * + * Arguments: --- + * + * Returns: Zero if OK, nonzero on failure. + * + * Use: Becomes a daemon. + */ + +extern int daemonize(void); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/man/Makefile.am b/man/Makefile.am index 6fb3016..270e236 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -37,11 +37,11 @@ MANPAGES = \ MANPAGESEXT = \ alloc.3 arena.3 assoc.3 atom.3 base32.3 base64.3 bits.3 bres.3 \ - buf.3 conn.3 crc32.3 darray.3 dspool.3 dstr.3 env.3 exc.3 \ - fdflags.3 fwatch.3 hash.3 ident.3 lbuf.3 lock.3 mLib.3 mdwopt.3 \ - pkbuf.3 pool.3 quis.3 report.3 sel.3 selbuf.3 selpk.3 sig.3 \ - str.3 sub.3 sym.3 testrig.3 trace.3 tv.3 url.3 hex.3 fdpass.3 \ - macros.3 unihash.3 + buf.3 conn.3 crc32.3 darray.3 daemonize.3 dspool.3 dstr.3 env.3 \ + exc.3 fdflags.3 fwatch.3 hash.3 ident.3 lbuf.3 lock.3 mLib.3 \ + mdwopt.3 pkbuf.3 pool.3 quis.3 report.3 sel.3 selbuf.3 selpk.3 \ + sig.3 str.3 sub.3 sym.3 testrig.3 trace.3 tv.3 url.3 hex.3 fdpass.3 \ + macros.3 unihash.3 versioncmp.3 install-man: $(MANPAGES) @$(NORMAL_INSTALL) diff --git a/man/daemonize.3 b/man/daemonize.3 new file mode 100644 index 0000000..1482bed --- /dev/null +++ b/man/daemonize.3 @@ -0,0 +1,41 @@ +.\" -*-nroff-*- +.TH daemonize 3 "6 January 2007" "Straylight/Edgeware" "mLib utilities library" +.SH NAME +daemonize \- become a background process +.\" @detachtty +.\" @daemonize +.SH SYNOPSIS +.nf +.B "#include " + +.B "void detachtty(void);" +.B "int daemonize(void);" +.fi +.SH DESCRIPTION +The +.B daemonize +function causes the current process to become a background process. It +detaches from its controlling terminal and arranges never to acquire +another controlling terminal. If it fails for some reason (probably +because +.BR fork (2) +failed), +.B daemonize +returns \-1 and sets +.BR errno ; +on success, it returns 0. +.PP +The +.B detachtty +does half of the job of +.BR daemonize : +it detaches from its controlling terminal, and calls +.BR setsid (2) +and +.BR fork (2) +so that it can't acquire a new controlling terminal in future. Errors +are ignored. +.SH SEE ALSO +.BR mLib (3). +.SH AUTHOR +Mark Wooding, diff --git a/man/versioncmp.3 b/man/versioncmp.3 new file mode 100644 index 0000000..0a4c6d7 --- /dev/null +++ b/man/versioncmp.3 @@ -0,0 +1,56 @@ +.\" -*-nroff-*- +.TH versioncmp 3 "6 January 2007" "Straylight/Edgeware" "mLib utilities library" +.SH NAME +versioncmp \- compare Debian-format version numbers +.\" @versioncmp +.SH SYNOPSIS +.nf +.B "#include " + +.BI "int versioncmp(const char *" va ", const char *" vb ");" +.fi +.SH DESCRIPTION +The +.B versioncmp +function compares version strings. +.PP +The format of version numbers considered is +.IP +.RI [ epoch +.BR : ] +.I main +.RB [ \- +.IR sub ] +.PP +The +.I main +part may contain colons or hyphens if there is an +.I epoch +or +.IR sub , +respectively. Version strings are compared componentwise: first epochs, +then main parts, and finally subparts. +.PP +The component comparison is done as follows. First, the initial +subsequence of nondigit characters is extracted from each string, and +these are compared lexicographically, using ASCII ordering, except that +letters precede non-letters. If both are the same, an initial sequence +of digits is extracted from the remaining parts of the version strings, +and these are compared numerically (an empty sequence being considered +to have the value zero). This process is repeated until we have a +winner or until both strings are exhausted. +.PP +The return value is 0 if the two strings are equal, \-1 if +.I va +is older than +.IR vb , +or +1 if +.I va +is newer than +.IR vb . +.SH SEE ALSO +.BR mLib (3). +.PP +.IR "Debian Policy Manual" . +.SH AUTHOR +Mark Wooding, diff --git a/versioncmp.c b/versioncmp.c new file mode 100644 index 0000000..335098b --- /dev/null +++ b/versioncmp.c @@ -0,0 +1,192 @@ +/* -*-c-*- + * + * $Id$ + * + * Compare version numbers using the Debian algorithm + * + * (c) 2007 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include + +#include "versioncmp.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @versioncmp@ --- * + * + * Arguments: @const char *va, *vb@ = two version strings + * + * Returns: Less than, equal to, or greater than zero, according to + * whether @va@ is less than, equal to, or greater than @vb@. + * + * Use: Compares version number strings. + * + * The algorithm is an extension of the Debian version + * comparison algorithm. A version number consists of three + * components: + * + * [EPOCH :] MAIN [- SUB] + * + * The MAIN part may contain colons or hyphens if there is an + * EPOCH or SUB, respectively. Version strings are compared + * componentwise: first epochs, then main parts, and finally + * subparts. + * + * The component comparison is done as follows. First, the + * initial subsequence of nondigit characters is extracted from + * each string, and these are compared lexicographically, using + * ASCII ordering, except that letters precede non-letters. If + * both are the same, an initial sequence of digits is extracted + * from the remaining parts of the version strings, and these + * are compared numerically (an empty sequence being considered + * to have the value zero). This process is repeated until we + * have a winner or until both strings are exhausted. + */ + +struct vinfo { + const char *e, *el; + const char *m, *ml; + const char *s, *sl; +}; + +static int vint(const char **vv, const char *vl) +{ + int n = 0; + const char *v = *vv; + int ch; + + while (v < vl) { + ch = *v; + if (!isdigit((unsigned char)ch)) + break; + v++; + n = n * 10 + (ch - '0'); + } + *vv = v; + return (n); +} + +static const char *vchr(const char **vv, const char *vl) +{ + const char *v = *vv; + const char *b = v; + int ch; + + while (v < vl) { + ch = *v; + if (isdigit((unsigned char)ch)) + break; + v++; + } + *vv = v; + return (b); +} + +#define CMP(x, y) ((x) < (y) ? -1 : +1) + +static int vcmp(const char *va, const char *val, + const char *vb, const char *vbl) +{ + const char *pa, *pb; + int ia, ib; + + for (;;) { + + /* --- See if we're done --- */ + + if (va == val && vb == vbl) + return (0); + + /* --- Compare nondigit portions --- */ + + pa = vchr(&va, val); pb = vchr(&vb, vbl); + for (;;) { + if (pa == va && pb == vb) + break; + else if (pa == va) + return (-1); + else if (pb == vb) + return (+1); + else if (*pa == *pb) { + pa++; pb++; + continue; + } else if (isalpha((unsigned char)*pa) == isalpha((unsigned char)*pb)) + return (CMP(*pa, *pb)); + else if (isalpha((unsigned char)*pa)) + return (-1); + else + return (+1); + } + + /* --- Compare digit portions --- */ + + ia = vint(&va, val); ib = vint(&vb, vbl); + if (ia != ib) + return (CMP(ia, ib)); + } +} + +static void vsplit(const char *v, struct vinfo *vi) +{ + const char *p; + size_t n; + + if ((p = strchr(v, ':')) == 0) + vi->e = vi->el = 0; + else { + vi->e = v; + vi->el = p; + v = p + 1; + } + + n = strlen(v); + if ((p = strrchr(v, '-')) == 0) + vi->s = vi->sl = 0; + else { + vi->s = p + 1; + vi->sl = v + n; + n = p - v; + } + + vi->m = v; + vi->ml = v + n; +} + +int versioncmp(const char *va, const char *vb) +{ + struct vinfo via, vib; + int rc; + + vsplit(va, &via); vsplit(vb, &vib); + if ((rc = vcmp(via.e, via.el, vib.e, vib.el)) != 0 || + (rc = vcmp(via.m, via.ml, vib.m, vib.ml)) != 0 || + (rc = vcmp(via.s, via.sl, vib.s, vib.sl)) != 0) + return (rc); + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/versioncmp.h b/versioncmp.h new file mode 100644 index 0000000..dfd2788 --- /dev/null +++ b/versioncmp.h @@ -0,0 +1,78 @@ +/* -*-c-*- + * + * $Id$ + * + * Compare version numbers using the Debian algorithm + * + * (c) 2007 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#ifndef MLIB_VERSIONCMP_H +#define MLIB_VERSIONCMP_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Functions provided ------------------------------------------------*/ + +/* --- @versioncmp@ --- * + * + * Arguments: @const char *va, *vb@ = two version strings + * + * Returns: Less than, equal to, or greater than zero, according to + * whether @va@ is less than, equal to, or greater than @vb@. + * + * Use: Compares version number strings. + * + * The algorithm is an extension of the Debian version + * comparison algorithm. A version number consists of three + * components: + * + * [EPOCH :] MAIN [- SUB] + * + * The MAIN part may contain colons or hyphens if there is an + * EPOCH or SUB, respectively. Version strings are compared + * componentwise: first epochs, then main parts, and finally + * subparts. + * + * The component comparison is done as follows. First, the + * initial subsequence of nondigit characters is extracted from + * each string, and these are compared lexicographically, using + * ASCII ordering, except that letters precede non-letters. If + * both are the same, an initial sequence of digits is extracted + * from the remaining parts of the version strings, and these + * are compared numerically (an empty sequence being considered + * to have the value zero). This process is repeated until we + * have a winner or until both strings are exhausted. + */ + +extern int versioncmp(const char */*va*/, const char */*vb*/); + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif -- [mdw]