On Wed, Oct 06, 2010 at 01:34:32PM +0200, Matteo Cypriani wrote: > On Wed, 6 Oct 2010 09:12:34 +0300, Peter Pentchev wrote: > > env DEB_BUILD_HARDENING=0 cc -O2 -g -o dma-migrate dma-migrate.c > > > > ...and, if that suddenly happens to work (it shouldn't, but still), > with: > > > > env DEB_BUILD_HARDENING=1 cc -O2 -g -o dma-migrate dma-migrate.c > > (with the hardening-wrapper package installed) > > > > ...and show me the output (to stderr, mostly) and the strace output for > > both cases? > > OK so here are the result without hardening (it still does not work, so I > did not try with hardening).
Ah. Now I have a suspicion... low-probability, but who knows. Once more, please? :) Sorry if I'm bothering you too much - and *of course* it's no problem that you build these programs only when you actually can make the time to do so :) So... can you build this one - without hardening would be enough? Thanks for your patience and help! G'luck, Peter -- Peter Pentchev [email protected] [email protected] [email protected] PGP key: http://people.FreeBSD.org/~roam/roam.key.asc Key fingerprint FDBA FD79 C26F 3C51 C95E DF9E ED18 B68D 1619 4553 Thit sentence is not self-referential because "thit" is not a word.
/*-
* Copyright (c) 2010 Peter Pentchev
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <regex.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef __printflike
#ifdef __GNUC__
#define __printflike(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#else
#define __printflike(fmtarg, firstvararg)
#endif
#endif
#define DEFAULT_SPOOLDIR "/var/spool/dma"
static int verbose = 0;
static char copybuf[BUFSIZ];
static int dma_migrate(int, const char *);
static int open_locked(const char *, int, ...);
static void cleanup_file(int, char *);
static void usage(int);
static void version(void);
static void debug(const char *, ...) __printflike(1, 2);
int
main(int argc, char **argv)
{
const char *spooldir;
int hflag, Vflag, errs, fd, res;
char ch;
DIR *d;
struct dirent *e;
struct stat sb;
fprintf(stderr, "RDBG 001 before srandom()\n");
srandom((unsigned long)((time(NULL) ^ getpid()) + ((uintptr_t)argv)));
hflag = Vflag = 0;
spooldir = DEFAULT_SPOOLDIR;
fprintf(stderr, "RDBG 002 before getopt()\n");
while (ch = getopt(argc, argv, "d:hVv"), ch != -1)
switch (ch) {
case 'd':
fprintf(stderr, "RDBG 002d '%s'\n", optarg);
spooldir = optarg;
break;
case 'h':
fprintf(stderr, "RDBG 002h\n");
hflag = 1;
break;
case 'V':
fprintf(stderr, "RDBG 002V\n");
Vflag = 1;
break;
case 'v':
fprintf(stderr, "RDBG 002v\n");
verbose = 1;
break;
case '?':
fprintf(stderr, "RDBG 002?\n");
usage(1);
/* NOTREACHED */
default:
fprintf(stderr, "Internal problem: unexpected getopt() return value: %d\n", ch);
return (1);
}
fprintf(stderr, "RDBG 002.1 after the getopt loop\n");
if (Vflag)
version();
if (hflag)
usage(0);
if (hflag || Vflag)
exit(0);
fprintf(stderr, "RDBG 003 after getopt()\n");
argc -= optind;
argv += optind;
fprintf(stderr, "RDBG 004 argc = %d argv = %p\n", argc, argv);
/* Let's roll! */
if (chdir(spooldir) == -1)
err(1, "Could not change into spool directory %s", spooldir);
fprintf(stderr, "RDBG 005 after chdir()\n");
if (d = opendir("."), d == NULL)
err(1, "Could not read spool directory %s", spooldir);
fprintf(stderr, "RDBG 005 after opendir()\n");
errs = 0;
while (e = readdir(d), e != NULL) {
/* Do we care about this entry? */
fprintf(stderr, "RDBG 006 read a dir entry %s\n", e->d_name);
debug("Read a directory entry: %s\n", e->d_name);
if (strncmp(e->d_name, "tmp_", 4) == 0 ||
e->d_name[0] == 'M' || e->d_name[0] == 'Q' ||
(e->d_type != DT_REG && e->d_type != DT_UNKNOWN)) {
fprintf(stderr, "RDBG 007 skipping it\n");
continue;
}
if (e->d_type == DT_UNKNOWN) {
fprintf(stderr, "RDBG 008 additional stat()\n");
if (stat(e->d_name, &sb) == -1 || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "RDBG 009 skipping it\n");
continue;
}
fprintf(stderr, "RDBG 010 not skipping a DT_UNKNOWN entry\n");
}
fprintf(stderr, "RDBG 011 want to process it\n");
debug("- want to process it\n");
/* Try to lock it - skip it if dma is delivering the message */
if (fd = open_locked(e->d_name, O_RDONLY|O_NDELAY), fd == -1) {
fprintf(stderr, "RDBG 012 open_locked() failed\n");
debug("- seems to be locked, skipping\n");
continue;
}
/* Okay, convert it to the M/Q schema */
fprintf(stderr, "RDBG 013 before dma_migrate()\n");
res = dma_migrate(fd, e->d_name);
fprintf(stderr, "RDBG 014 after dma_migrate(), res = %d\n", res);
close(fd);
if (res == -1)
errs++;
fprintf(stderr, "RDBG 015 on with the loop\n");
}
fprintf(stderr, "RDBG 016 finished, errs = %d\n", errs);
if (errs)
debug("Finished, %d conversion errors\n", errs);
else
debug("Everything seems to be all right\n");
fprintf(stderr, "RDBG 017 returning %d\n", errs && 1);
return (errs && 1);
}
static int
dma_migrate(int fd, const char *fname)
{
const char *id;
char *mname, *qname, *tempname, *sender, *recp, *line, *recpline;
int mfd, qfd, tempfd;
struct stat sb;
FILE *fp, *qfp, *mfp;
size_t sz, len;
static regex_t *qidreg = NULL;
mfd = tempfd = qfd = -1;
mname = qname = sender = recp = line = NULL;
fp = qfp = NULL;
if (fstat(fd, &sb) == -1) {
warn("Could not fstat(%s)", fname);
return (-1);
}
/*
* Let's just blithely assume that the queue ID *is* the filename,
* since that's the way dma did things so far.
* Well, okay, let's check it.
*/
if (qidreg == NULL) {
regex_t *nreg;
if ((nreg = malloc(sizeof(*qidreg))) == NULL) {
warn("Could not allocate memory for a regex");
return (-1);
}
if (regcomp(nreg, "^[a-fA-F0-9]\\+\\.[a-fA-F0-9]\\+$", 0)
!= 0) {
warnx("Could not compile a dma queue ID regex");
free(nreg);
return (-1);
}
qidreg = nreg;
}
if (regexec(qidreg, fname, 0, NULL, 0) != 0) {
warnx("The name '%s' is not a valid dma queue ID", fname);
return (-1);
}
id = fname;
debug(" - queue ID %s\n", id);
if (asprintf(&mname, "M%s", id) == -1 ||
asprintf(&tempname, "tmp_%s", id) == -1 ||
asprintf(&qname, "Q%s", id) == -1 ||
mname == NULL || tempname == NULL || qname == NULL)
goto fail;
/* Create the message placeholder early to avoid races */
mfd = open_locked(mname, O_CREAT | O_EXCL | O_RDWR, 0600);
if (mfd == -1) {
warn("Could not create temporary file %s", mname);
goto fail;
}
if (stat(qname, &sb) != -1 || errno != ENOENT ||
stat(tempname, &sb) != -1 || errno != ENOENT) {
warnx("Some of the queue files for %s already exist", fname);
goto fail;
}
debug(" - mfd %d names %s, %s, %s\n", mfd, mname, tempname, qname);
fp = fdopen(fd, "r");
if (fp == NULL) {
warn("Could not reopen the descriptor for %s", fname);
goto fail;
}
/* Parse the header of the old-format message file */
/* ...sender... */
if (getline(&sender, &sz, fp) == -1) {
warn("Could not read the initial line from %s", fname);
goto fail;
}
sz = strlen(sender);
while (sz > 0 && (sender[sz - 1] == '\n' || sender[sz - 1] == '\r'))
sender[--sz] = '\0';
if (sz == 0) {
warnx("Empty sender line in %s", fname);
goto fail;
}
debug(" - sender %s\n", sender);
/* ...recipient(s)... */
len = strlen(fname);
recpline = NULL;
while (1) {
if (getline(&line, &sz, fp) == -1) {
warn("Could not read a recipient line from %s", fname);
goto fail;
}
sz = strlen(line);
while (sz > 0 &&
(line[sz - 1] == '\n' || line[sz - 1] == '\r'))
line[--sz] = '\0';
if (sz == 0) {
free(line);
line = NULL;
break;
}
if (recp == NULL &&
strncmp(line, fname, len) == 0 && line[len] == ' ') {
recp = line + len + 1;
recpline = line;
} else {
free(line);
}
line = NULL;
}
if (recp == NULL) {
warnx("Could not find its own recipient line in %s", fname);
goto fail;
}
/* ..phew, finished with the header. */
tempfd = open_locked(tempname, O_CREAT | O_EXCL | O_RDWR, 0600);
if (tempfd == -1) {
warn("Could not create a queue file for %s", fname);
goto fail;
}
qfp = fdopen(tempfd, "w");
if (qfp == NULL) {
warn("Could not fdopen(%s) for %s", tempname, fname);
goto fail;
}
mfp = fdopen(mfd, "w");
if (mfp == NULL) {
warn("Could not fdopen(%s) for %s", mname, fname);
goto fail;
}
fprintf(qfp, "ID: %s\nSender: %s\nRecipient: %s\n", id, sender, recp);
fflush(qfp);
fsync(tempfd);
/* Copy the message file over to mname */
while ((sz = fread(copybuf, 1, sizeof(copybuf), fp)) > 0)
if (fwrite(copybuf, 1, sz, mfp) != sz) {
warn("Could not copy the message from %s to %s",
fname, mname);
goto fail;
}
if (ferror(fp)) {
warn("Could not read the full message from %s", fname);
goto fail;
}
fflush(mfp);
fsync(mfd);
if (rename(tempname, qname) == -1) {
warn("Could not rename the queue file for %s", fname);
goto fail;
}
qfd = tempfd;
tempfd = -1;
if (unlink(fname) == -1) {
warn("Could not remove the old converted file %s", fname);
goto fail;
}
fclose(fp);
fclose(qfp);
free(sender);
free(line);
free(recpline);
free(mname);
free(qname);
free(tempname);
return (0);
fail:
if (fp != NULL)
fclose(fp);
if (qfp != NULL)
fclose(qfp);
if (sender != NULL)
free(sender);
if (line != NULL)
free(line);
if (recpline != NULL)
free(recpline);
cleanup_file(mfd, mname);
cleanup_file(qfd, qname);
cleanup_file(tempfd, tempname);
return (-1);
}
static void
cleanup_file(int fd, char *fname)
{
if (fd != -1) {
close(fd);
unlink(fname);
}
if (fname != NULL)
free(fname);
}
static void
usage(int ferr)
{
const char *s =
"Usage:\tdma-migrate [-hVv] [-d spooldir]\n"
"\t-d\tspecify the spool directory (" DEFAULT_SPOOLDIR ")\n"
"\t-h\tdisplay program usage information and exit\n"
"\t-V\tdisplay program version information and exit\n"
"\t-v\tverbose operation - display diagnostic messages";
if (ferr)
errx(1, "%s", s);
puts(s);
}
static void
version(void)
{
printf("dma-migrate 0.01 (dma 0.0.2010.06.17)\n");
}
static void
debug(const char *fmt, ...)
{
va_list v;
if (verbose < 1)
return;
va_start(v, fmt);
vfprintf(stderr, fmt, v);
va_end(v);
}
static int
open_locked(const char *fname, int flags, ...)
{
int mode = 0;
#ifndef O_EXLOCK
int fd, save_errno;
#endif
if (flags & O_CREAT) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
}
#ifndef O_EXLOCK
fd = open(fname, flags, mode);
if (fd < 0)
return(fd);
if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
save_errno = errno;
close(fd);
errno = save_errno;
return(-1);
}
return(fd);
#else
return(open(fname, flags|O_EXLOCK, mode));
#endif
}
signature.asc
Description: Digital signature

