On Wed, Oct 06, 2010 at 02:31:45PM +0200, Matteo Cypriani wrote: > > So... can you build this one - without hardening would be enough? > > # ./dma-migrate -v > RDBG 001 before srandom() > RDBG 002 before getopt() > RDBG 002v > Internal problem: unexpected getopt() return value: 255 [snip] > > Sounds like a progress…
Argh! Okay, I see the problem now. It's mostly a case of me being a bit stupid at times, though this particular mistake is one I hadn't made in almost ten years - and as luck would have it, GCC does indeed treat char as unsigned on PowerPC, so the getopt() loop never finishes and dma-migrate never reaches the point where it will actually migrate stuff. Mmmmkay, here's another version of the tool for you to test, although I'm pretty sure it will just work now. If it works, I'll upload a fixed package tonight or tomorrow, and I'll see if the release team will approve a freeze exception. So... try this? (basically a "char ch" to "int ch" fix) I'm 99.5% sure that this *is* the problem, so I'll prepare a package for upload. G'luck, Peter -- Peter Pentchev r...@space.bg r...@ringlet.net r...@freebsd.org PGP key: http://people.FreeBSD.org/~roam/roam.key.asc Key fingerprint FDBA FD79 C26F 3C51 C95E DF9E ED18 B68D 1619 4553 If I had finished this sentence,
/*- * 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; int 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