Beispiel #1
0
/*
 * Check to make sure that the current process doesn't have the lock on a
 * shared-memory FIFO.
 *
 * Precondition:
 *      The FIFO is not locked by this process.
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO data-structure.
 *      havLck          Pointer to indicator to be set.
 * Returns:
 *      0               Success. The current process doesn't have the FIFO
 *                      locked.
 *      EINVAL          The current process has the FIFO locked.  Error-message
 *                      logged.
 *      EINVAL          "shm" uninitialized. Error-message logged.
 *      ECANCELED       Operating-system failure. Error-message logged.
 */
static int
checkUnlocked(
    const struct shmhandle* const       shm)
{
    int status;

    if (0 > shm->semid) {
        log_error("Invalid semaphore ID: %d", shm->semid);
        status = EINVAL;
    }
    else {
        int     semval = semctl(shm->semid, SI_LOCK, GETVAL);
        int     pid = semctl(shm->semid, SI_LOCK, GETPID);

        if (-1 == semval || -1 == pid) {
            log_syserr("semctl() failure");
            status = ECANCELED;
        }
        else {
            if ((0 == semval) && (getpid() == pid)) {
                log_error("FIFO already locked by this process: %d", pid);
                status = EINVAL;
            }
            else {
                status = 0;
            }
        }
    }

    return status;
}
Beispiel #2
0
/*
 * Check to make sure that the current process has the lock on a shared-memory
 * FIFO.
 *
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO data-structure.
 *      havLck          Pointer to indicator to be set.
 * Returns:
 *      0               Success. The current process has the FIFO locked.
 *      EINVAL          The current process doesn't have the FIFO locked.
 *                      Error-message logged.
 *      EINVAL          "shm" uninitialized. Error-message logged.
 *      ECANCELED       Operating-system failure. Error-message logged.
 */
static int
checkLocked(
    const struct shmhandle* const       shm)
{
    int status;

    if (0 > shm->semid) {
        log_error("Invalid semaphore ID: %d", shm->semid);
        status = EINVAL;
    }
    else {
        int     semval = semctl(shm->semid, SI_LOCK, GETVAL);
        int     pid = semctl(shm->semid, SI_LOCK, GETPID);

        if (-1 == semval || -1 == pid) {
            log_syserr("semctl() failure");
            status = ECANCELED;
        }
        else {
            if (0 != semval) {
                log_error("FIFO not locked: %d", semval);
                status = EINVAL;
            }
            else if (getpid() != pid) {
                log_error("FIFO locked by another process: %d", pid);
                status = EINVAL;
            }
            else {
                status = 0;
            }
        }
    }

    return status;
}
Beispiel #3
0
/*
 * Locks a shared-memory FIFO.
 *
 * Preconditions:
 *      The shared-memory FIFO is unlocked.
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO data-structure.
 * Returns:
 *      0               Success
 *      ECANCELED       Operating-system failure. Error-message logged.
 *      EINVAL          "shm" is uninitialized. Error-message logged.
 *      EINVAL          Semaphore  is uninitialized. Error-message logged.
 *      EINVAL          FIFO is already locked by this process. Error-message
 *                      logged.
 */
static int
shmfifo_lock(
    const struct shmhandle* const       shm)
{
    int status = checkUnlocked(shm);

    if (0 == status) {
        struct sembuf op[1];

        /*  printf("called shmfifo_lock semid: %d in process %d\n",shm->semid,
         *  getpid());
         *  printf("<%d>locking %d\n",getpid(),shm->semid); */

        op[0].sem_num = SI_LOCK;
        op[0].sem_op = -1;
        op[0].sem_flg = 0;

        /* dvbs_multicast(1) used to hang here */
        if (semop (shm->semid, op, 1) == -1) {
            log_syserr("semop(2) failure");
            status = ECANCELED;
        }
        else {
            status = 0;                 /* success */
        }

        /*   printf("<%d> locked\n",getpid()); */
    }

    return status;
}
Beispiel #4
0
/*
 * Unlocks a shared-memory FIFO.
 *
 * Precondition:
 *      The FIFO is locked by this process.
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO data-structure.
 * Returns:
 *      0               Success.
 *      ECANCELED       Operating-system failure. Error-message logged.
 *      EINVAL          "shm" is uninitialized.
 *      EINVAL          FIFO is locked by this process. Error-message logged.
 */
static int
shmfifo_unlock(
    const struct shmhandle* const       shm)
{
    int status = checkLocked(shm);

    if (0 == status) {
        struct sembuf   op[1];

        /*   printf("<%d> unlocking %d\n",getpid(),shm->semid); */

        op[0].sem_num = SI_LOCK;
        op[0].sem_op = 1;
        /*op[0].sem_flg = SEM_UNDO; */
        op[0].sem_flg = 0;

        if (semop(shm->semid, op, 1) == -1) {
            log_syserr("semop(2) failure");
            status = ECANCELED;
        }
        else {
            status = 0;                 /* success */
        }

        /*   printf("unlocked. done\n");  */
    }

    return status;
}
Beispiel #5
0
/*
 * Waits for a shared-memory FIFO to be notified. The shared-memory FIFO must
 * be locked.
 *
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO.
 *      semIndex        The index of the semaphore to wait upon. One of
 *                      SI_READER or SI_WRITER.
 * Returns:
 *      0               Success. Another thread of control has locked and
 *                      released the FIFO. Upon return, the shared-memory FIFO
 *                      shall be locked.
 *      EINVAL          "shm" uninitialized. Error-message logged.
 *      EINVAL          The FIFO isn't locked by the current process.
 *                      Error-message logged.
 *      EINVAL          "semIndex" isn't SI_READER or SI_WRITER.
 *      ECANCELED       Operating-system failure. Error-message logged.
 * Raises:
 *      SIGSEGV if "shm" is NULL.
 */
static int
shmfifo_wait(
    const struct shmhandle* const       shm,
    const SemIndex                      semIndex)
{
    int status = vetSemIndex(semIndex);

    if (0 == status) {
        /* Release the lock */
        if ((status = shmfifo_unlock(shm)) == 0) {
            struct sembuf   op[1];

            /* Wait for a notification from the other process */
            op[0].sem_num = semIndex;
            op[0].sem_op = -1;
            op[0].sem_flg = 0;

            if (semop(shm->semid, op, 1) == -1) {
                log_syserr("semop() failure");
                status = ECANCELED;
            }

            /* Reacquire the lock */
            if (shmfifo_lock(shm) != 0) {
                status = ECANCELED;
            }                       /* lock reacquired */
        }                           /* lock released */
    }                               /* valid "semIndex" */

    return status;
}
Beispiel #6
0
int main(
        const int argc,
        const char* const * argv)
{
    int exitCode = 1;

    if (log_init(argv[0])) {
        log_syserr("Couldn't initialize logging module");
        exitCode = EXIT_FAILURE;
    }
    else {
        if (CUE_SUCCESS == CU_initialize_registry()) {
            CU_Suite* testSuite = CU_add_suite(__FILE__, setup, teardown);

            if (NULL != testSuite) {
                if (CU_ADD_TEST(testSuite, test_socketpair)) {
                    CU_basic_set_mode(CU_BRM_VERBOSE);
                    (void) CU_basic_run_tests();
                }
            }

            exitCode = CU_get_number_of_tests_failed();
            CU_cleanup_registry();
        }

        log_fini();
    }

    return exitCode;
}
Beispiel #7
0
/*
 * Returns:
 *   0             Success.
 *   ENOENT        gethostbyname() failure.
 *   EAFNOSUPPORT  AF_INET address-family not supported.
 *   EMFILE        No more file descriptors available for this process.
 *   ENFILE        No more file descriptors available for the system.
 *   EACCES        The process does not have appropriate privileges.
 *   ENOBUFS       Insufficient resources were available in the system to
 *                 perform the operation.
 *   ENOMEM        Insufficient memory was available to fulfill the request.
 *   ENOSR         There were insufficient STREAMS resources available for the 
 *                 operation to complete.
 *   EADDRNOTAVAIL The specified address is not available from the local 
 *                 machine.
 *   ECONNREFUSED  The target address was not listening for connections or 
 *                 refused the connection request.
 *   EINTR         The attempt to establish a connection was interrupted by
 *                 delivery of a signal that was caught; the connection will be
 *                 established asynchronously.
 *   ENETUNREACH   No route to the network is present.
 *   EPROTOTYPE    The specified address has a different type than the socket 
 *                 bound to the specified peer address.
 *   ETIMEDOUT     The attempt to connect timed out before a connection was 
 *                 made.
 *   ECONNRESET    Remote host reset the connection request.
 *   EHOSTUNREACH  The destination host cannot be reached (probably because the
 *                 host is down or a remote router cannot reach it).
 *   ENETDOWN      The local interface used to reach the destination is down.
 */   
int
port_open(const char *remote, unsigned short port, int *const fdp)
{
        int status = ENOERR;
        int sock;
        struct sockaddr_in addr;

        if (addrbyhost(remote, &addr) != 0)
        {
                status = ENOENT;
                log_syserr("gethostbyname(%s)", remote);
                return status;
        }

        sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
                status = errno;
                log_syserr("socket");
                return status;
        }
#if 0 /* doesnt seem to help. See VOODOO in pqing.c */
        {
                const int optval = 1;
                if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
                                (char *) &optval, (int) sizeof(optval)) < 0)
                {
                        status = errno;
                        log_syserr("setsockopt SO_KEEPALIVE");
                        return status;
                }
        }
#endif

        addr.sin_port = htons(port);
        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
        {
                status = errno;
                log_syserr("connect");
                (void) close(sock);
                return status;
        }
        
        log_notice("NET \"%s\" %hu", remote, port);
        *fdp = sock;
        return status;
}
Beispiel #8
0
/*
 * Opens the backend database.
 *
 * ARGUMENTS:
 *      backend         Pointer to pointer to backend structure.  Shall not be
 *                      NULL.  Upon successful return, "*backend" will be set.
 *                      The client should call "beClose(*backend)" when the
 *                      backend is no longer needed.
 *      dir             Pathname of the parent directory of the database.
 *                      Shall not be NULL.  The client can free it upon return.
 *      forWriting      Open the database for writing? 0 <=> no
 * RETURNS:
 *      0               Success.  "*backend" is set.
 *      ENOMEM          System error.  "log_add()" called.
 *      EIO             Backend database error.  "log_add()" called.
 */
RegStatus
beOpen(
    Backend** const     backend,
    const char* const   dir,
    int                 forWriting)
{
    RegStatus   status;
    Backend*    back = (Backend*)malloc(sizeof(Backend));

    assert(NULL != dir);

    if (NULL == back) {
        log_syserr("Couldn't allocate %lu bytes", (long)sizeof(Backend));
        status = ENOMEM;
    }
    else {
        DB_ENV*         env;
        DB*             db;
        StringBuf*      path;

        if (0 == (status = sb_new(&path, PATH_MAX))) {
            if (0 == (status = sb_cat(path, dir, "/", DB_DIRNAME))) {
                if (0 == (status = createDbHandle(path, &env, &db))) {
                    if (status = db->open(db, NULL, DB_FILENAME, NULL,
                            DB_BTREE, forWriting ? DB_CREATE : DB_RDONLY, 0)) {
                        log_add("Couldn't open database \"%s\" in \"%s\" "
                            "for %s", DB_FILENAME, path,
                            forWriting ? "writing" : "reading");
                        status = EIO;
                    }
                    else {
                        back->db = db;
                        back->cursor.dbCursor = NULL;
                        *backend = back;    /* success */
                    }                       /* "db" opened */

                    /*
                     * According to the documentation on DB->open(), if that
                     * call fails, then DB->close() must be called to discard
                     * the DB handle, so DB->close() is the termination
                     * counterpart of db_create() rather than of DB->open().
                     */
                    if (status) {
                        (void)db->close(db, 0);
                        (void)env->close(env, 0);
                    }
                }                       /* "env" allocated */
            }                           /* DB directory pathname created */

            sb_free(path);
        }                               /* "path" allocated */

        if (status)
            free(back);
    }                                   /* "back" allocated */

    return status;
}
Beispiel #9
0
/**
 * Returns a new file-reader.
 *
 * This function is thread-safe.
 *
 * @retval 0    Success.
 * @retval 1    Precondition failure. \c log_add() called.
 * @retval 2    O/S failure. \c log_add() called.
 */
int fileReaderNew(
    const char* const   pathname,   /**< [in] Pathname of file to read or
                                      *  NULL to read standard input stream */
    Fifo* const         fifo,       /**< [in] Pointer to FIFO into which to put
                                      *  data */
    Reader** const      reader)     /**< [out] Pointer to pointer to address of
                                      *  reader */
{
    int status = 0;                 /* default success */
    int fd;                         /* input file descriptor */
    bool isStandardInput = NULL == pathname;

    if (isStandardInput) {
        if ((fd = fileno(stdin)) == -1) {
            log_syserr(
                    "Couldn't get file-descriptor of standard input stream");
            status = 1;
        }
    }
    else {
        if ((fd = open(pathname, O_RDONLY)) == -1) {
            log_syserr("Couldn't open file \"%s\"", pathname);
            status = 1;
        }
    }

    if (0 == status) {
        if ((status = readerNew(fd, fifo, sysconf(_SC_PAGESIZE), reader)) 
                != 0) {
            log_add("Couldn't create new reader object");

            if (!isStandardInput)
                (void)close(fd);
        }
    }

    return status;
}
Beispiel #10
0
static void* read_from_fd(void* arg)
{
    int fd = *(int*)arg;

    //for (int n = 1; n <= sizeof(buf); n <<= 1) {
    for (;;) {
        int nbytes = read(fd, buf, sizeof(buf));
        if (nbytes <= 0) {
            log_syserr("read() failure");
            break;
        }
        (void)printf("Read %d bytes\n", nbytes);
    }
    return NULL;
}
Beispiel #11
0
/**
 * Returns an allocated, shared-memory structure. The returned structure is
 * unset: it doesn't reference a shared-memory FIFO. The client should call
 * \link shmfifo_free() \endlink when the structure is no longer needed.
 *
 * @retval !NULL        Pointer to an allocated shared-memory structure.
 * @retval NULL         Failure. An error message is logged.
 */
struct shmhandle* shmfifo_new(void)
{
    struct shmhandle*   shm =
        (struct shmhandle*)malloc(sizeof(struct shmhandle));

    if (NULL == shm) {
        log_syserr("Couldn't allocate %lu bytes",
            sizeof(struct shmhandle));
    }
    else {
        (void)memset(shm, 0, sizeof(*shm));

        shm->mem = NULL;        /* necessary because shmfifo_attach() checks */
    }

    return shm;
}
Beispiel #12
0
/**
 * There is data available on the feed. Read it into the buffer
 * then deal with what we got.
 *
 * @param ifd           [in] File-descriptor of the input data-feed
 * @retval 0            Success
 * @retval ENOMEM       Out of memory
 * @retval ENODATA      End of input data-feed
 */
int
feedTheXbuf(const int ifd)
{
	int status;
	size_t nn = 0;
	/* space available in buffer */
	ptrdiff_t remaining = (ptrdiff_t)theBuf->bufsiz - (theBuf->get - theBuf->base);

	if (remaining <= CHUNKSIZE) {
		if (theBuf->bufsiz >= maxProductSize) {
			log_warning(
			        "Data-product would exceed %lu bytes. Resetting input buffer.",
				maxProductSize);
			justify_xbuf(theBuf, 0);
		}

		log_info("Expanding input buffer size to %lu\n",
			(unsigned long)(2 * theBuf->bufsiz));

		theBuf = expand_xbuf(theBuf, theBuf->bufsiz);

		if (theBuf == NULL) {
			status = errno == 0 ? ENOMEM : errno;
			log_syserr("expand_xbuf");
			return status;
		}
	}

	status = (*read_feed)(ifd, (char *)theBuf->put, CHUNKSIZE, &nn);
	if(status != ENOERR)
	{
		log_errno(status, "read_feed");
		return status;
	}
	/* else */
	if(nn == 0)
		return ENODATA; /* end of file */
	/* else */
	/* usual case */
	/* assert(nn > 0); */
	theBuf->cnt += nn;
	theBuf->put += nn;
	return ENOERR;
}
Beispiel #13
0
/*
 * Creates a database environment handle
 *
 * ARGUMENTS:
 *      path            Pathname of the database directory.  Shall not be NULL.
 *                      The client can free it upon return.
 *      dbEnv           Pointer to a pointer to the database environment.  Shall
 *                      not be NULL.  "*dbEnv" is set upon successful return.
 * RETURNS:
 *      0               Success.  "*dbEnv" is set.
 *      ENOMEM          System error.  "log_add()" called.
 *      EIO             Backend database error.  "log_add()" called.
 */
static RegStatus
createEnvHandle(
    const char* const   path,
    DB_ENV** const      dbEnv)
{
    RegStatus   status;
    DB_ENV*     env;

    assert(NULL != path);

    log_list_clear();

    if (status = db_env_create(&env, 0)) {
        log_syserr("Couldn't create environment handle for database: %s",
            db_strerror(status));
        status = ENOMEM;
    }
    else {
        env->set_errcall(env, logDbError);

        if (status = env->set_isalive(env, is_alive)) {
            log_add("Couldn't register \"is_alive()\" function for "
                "database \"%s\"", path);
            status = EIO;
        }
        else {
            static const unsigned      threadCount = 256;

            if (status = env->set_thread_count(env, threadCount)) {
                log_add("Couldn't set thread count to %u for database \"%s\"",
                    threadCount, path);
                status = EIO;
            }
            else {
                *dbEnv = env;
            }
        }

        if (status)
            (void)env->close(env, 0);
    }                                   /* "env" allocated */

    return status;
}
Beispiel #14
0
/*
 * Constructs a path name for the database.
 *
 * Arguments:
 *      path            Pathname of the database directory.  Shall not be NULL.
 *                      The client can free it upon return.
 *      ext             Extension for the database path name.
 * Returns:
 *      NULL            System error.  "log_add()" called.
 *      else            Pointer to the path name of the database.  The
 *                      client should call "free()" when the path name is no
 *                      longer needed.
 */
static char*
makeDatabasePath(
    const char* const   path,
    const char* const   ext)
{
    static const size_t lenFilename = sizeof(DB_FILENAME) - 1;
    size_t              lenPath = strlen(path);
    size_t              len = strlen(path) + 1 + lenFilename + strlen(ext) + 1;
    char*               buf = (char*)malloc(len);

    if (NULL == buf) {
        log_syserr("Couldn't allocate %lu bytes", (unsigned long)len);
    }
    else {
        (void)strcpy(strcpy(strcpy(strcpy(buf, path) + lenPath, "/") + 1, 
            DB_FILENAME) + lenFilename, ext);
    }

    return buf;
}
Beispiel #15
0
/**
 * Attaches a data-structure to its shared-memory FIFO.
 *
 * @retval  1   Success.
 * @retval -1   The data-structure is already attached to a shared-
 *              memory FIFO. An error message is logged.
 * @retval -1   The shared-memory FIFO reference by \e shm couldn't be
 *              attached. An error message is logged.
 */
int shmfifo_attach(
    struct shmhandle* const     shm)    /**< Pointer to the data-structure. */
{
  void* mem;

  if (shm->mem)
    {
      log_error ("attempt to attach already attached mem?\n");
      return -1;
    }

  if ((mem = shmat(shm->sid, 0, 0)) == (void*)-1) {
      log_syserr("Couldn't attach to shared-memory: sid=%d", shm->sid);
      return -1;
  }

  shm->mem = mem;

  return 1;
}
Beispiel #16
0
/**
 * Initializes this module.
 * 
 * @param readfunct     [in] The function that reads the data
 * @param maxProdSize   [in] The size, in bytes, of the largest expected 
 *                      data-product
 * @retval 0            Success
 * @retval ENOMEM       Out of memory
 */
int
initTheXbuf(
        int (*readfunct)(int ifd, char *buf, size_t nbytes, size_t *ngotp),
        const unsigned long maxProdSize)
{
	read_feed = readfunct;
    maxProductSize = maxProdSize > INIT_CIRCBUFSIZE ? maxProdSize : INIT_CIRCBUFSIZE;

	if(theBuf == NULL)
	{
		theBuf = new_xbuf(INIT_CIRCBUFSIZE);
		if(theBuf == NULL)
		{
			const int status = errno == 0 ? ENOMEM : errno;
			log_syserr("new_xbuf");
			return status;
		}
	}
	return ENOERR;
}
Beispiel #17
0
/*
 * Notifies the reader or writer process.
 *
 * Arguments:
 *      shm             Pointer to the shared-memory FIFO data-structure.
 *      semIndex        Which process to notify. One of SI_WRITER or SI_READER.
 * Returns:
 *      0               Success
 *      ECANCELED       Operating-system failure. Error-message logged.
 *      EINVAL          The FIFO isn't locked by the current process.
 *                      Error-message logged.
 *      EINVAL          "which" isn't SI_WRITER or SI_READER. Error-message
 *                      logged.
 * Precondition:
 *      The FIFO is locked by the current process.
 */
static int
shmfifo_notify(
    const struct shmhandle*     shm,
    const SemIndex              which)
{
    int status = checkLocked(shm);

    if (0 == status) {
        if ((status = vetSemIndex(which)) == 0) {
            if (semctl(shm->semid, which, SETVAL, 1)) {
                log_syserr("semctl() failure");
                status = ECANCELED;
            }
            else {
                status = 0;
            }
        }
    }

    return status;
}
Beispiel #18
0
/**
 * Forks the current process in the context of the LDM.  Does whatever's
 * necessary before and after the fork to ensure correct behavior.  Terminates
 * the child process if the fork() was successful but an error occurs.
 *
 * @retval -1  Failure. "log_add()" called.
 * @retval  0  Success. The calling process is the child.
 * @return              PID of child process. The calling process is the parent.
 */
pid_t ldmfork(void)
{
    pid_t       pid;

    if (reg_close()) {
        pid = -1;
    }
    else {
        pid = fork();

        if (0 == pid) {
            log_clear(); // So child process starts with no queued messages
            /* Child process */
        }
        else if (-1 == pid) {
            /* System error */
            log_syserr("Couldn't fork a child process");
        }
    }

    return pid;
}
Beispiel #19
0
/*
 * Sets the cursor to reference the first entry in the backend
 * database whose key is greater than or equal to a given key.
 *
 * ARGUMENTS:
 *      backend         Pointer to the backend database.  Shall have been
 *                      set by beOpen().  Shall not be NULL.
 *      key             Pointer to the starting key.  Shall not be NULL.  The
 *                      empty string obtains the first entry in the database,
 *                      if it exists.
 * RETURNS
 *      0               Success.
 *      EINVAL          The cursor is not initialized.
 *      ENOENT          The database is empty.
 *      EIO             Backend database error.  "log_add()" called.
 *      ENOMEM          System error.  "log_add()" called.
 */
RegStatus
beFirstEntry(
    Backend* const      backend,
    const char* const   key)
{
    RegStatus   status;
    Cursor*     cursor;

    assert(NULL != backend);
    assert(NULL != key);

    cursor = &backend->cursor;

    if (!cursor->dbCursor) {
        log_add("Cursor for backend database \"%s\" not initialized",
            getPath(backend->db));
        status = EINVAL;
    }
    else {
        char* const dupKey = strdup(key);

        if (NULL == dupKey) {
            log_syserr("Couldn't allocate %lu bytes", (long)strlen(key));
            status = ENOMEM;
        }
        else {
            backend->cursor.key.data = dupKey;
            backend->cursor.key.size = strlen(dupKey) + 1;

            if (EIO == (status = setCursor(&backend->cursor, DB_SET_RANGE))) {
                log_add("Couldn't set cursor for database \"%s\" to first "
                    "entry on or after key \"%s\"", getPath(backend->db), key);
            }
        }                               /* "dupKey" allocated */
    }

    return status;
}
Beispiel #20
0
/**
 * Returns a data-structure for accessing a shared-memory FIFO. Creates the
 * FIFO is it doesn't already exist.
 *
 * @retval !NULL        Pointer the data-structure for accessing the
 *                      shared-memory FIFO.
 * @retval NULL         Failure. An error message is logged.
 */
struct shmhandle* shmfifo_create(
    const int   npages,         /**< size of the FIFO in pages */
    const int   privsz,         /**< <size of the private portion of the FIFO
                                 in bytes */
    const int   nkey)           /**< Partial key associated with the FIFO  or
                                 \c -1 to obtain a private, shared-memory
                                 FIFO. */
{
    int                 shmSize = npages*getpagesize();
    int                 shmid;
    struct shmhandle*   shm = NULL;     /* default failure */
    key_t               key;

    if (nkey == -1) {
        shmid = shmget(IPC_PRIVATE, shmSize,
                IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
    }
    else {
        key = (key_t)(DVBS_ID + nkey);
        /*
         * IPC_EXCL creates an error condition if the memory already exists...
         * we can use the existing memory if the program has not changed the
         * size of the segment or the private structure size
         */
        shmid = shmget(key, shmSize,
            IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    }

    if (shmid == -1) {
        log_syserr("shmget() failure: npages=%d, nkey=%d",
            npages, nkey);
    }
    else {
        /* Temporarily attach to initialize the control structure. */
        struct shmprefix*       p = (struct shmprefix*)shmat(shmid, 0, 0);

        if (p == (void*)-1) {
            log_syserr("shmat() failure: id=%d", shmid);
        }
        else {
            int     semid;

            p->read = p->write = sizeof(struct shmprefix) + privsz;
            p->sz = shmSize;
            p->privsz = privsz;

            (void)memset((char*)p + sizeof(struct shmprefix), 0, privsz);
            (void)shmdt(p);

            p = NULL;

            /* Get semaphore */
            if (nkey == -1) {
                semid = semget(IPC_PRIVATE, SI_SEM_COUNT,
                    IPC_CREAT | IPC_EXCL + 0600);
            }
            else {
                /*
                 * IPC_EXCL not used in order to get existing semaphore if
                 * possible.
                 */
                semid = semget(key, SI_SEM_COUNT, IPC_CREAT + 0660);
            }

            if (semid == -1) {
                log_syserr("semget() failure");
            }
            else {
                unsigned short      values[SI_SEM_COUNT];
                union semun         arg;

                log_debug("shmfifo_create(): Got semaphore: pid=%d, semid=%d",
                    getpid(), semid);

                values[SI_LOCK] = 1;
                values[SI_WRITER] = 0;
                values[SI_READER] = 0;
                arg.array = values;

                if (semctl(semid, 0, SETALL, arg) == -1) {
                    log_syserr("semctl() failure: semid=%d",
                        semid);
                }
                else {
                    shm = shmfifo_new();

                    if (NULL != shm) {
                        shm->sid = shmid;
                        shm->privsz = privsz;
                        shm->sz = shmSize;
                        shm->semid = semid;
                    }
                }                       /* semaphore values set */
            }                           /* got semaphore set */
        }                               /* shared-memory was attached to "p" */
    }                                   /* got shared-memory segment ID */

    return shm;
}
Beispiel #21
0
int
main (int ac, char *av[])
{
  char *progname = av[0];
  int status;
  int seq_start = 0;
  stat_info *sinfo, *shead = NULL, *slast = NULL;
  int statusoff=0;

  /*
   * Set up error logging
   */
    if (log_init(progname)) {
        log_syserr("Couldn't initialize logging module");
        exit(1);
    }

  const char* pqfname = getQueuePath();

  /*
   * Check the environment for some options.
   * May be overridden by command line switches below.
   */
  {
    const char *ldmpqfname = getenv ("LDMPQFNAME");
    if (ldmpqfname != NULL)
      pqfname = ldmpqfname;
  }

  {
    extern int optind;
    extern int opterr;
    extern char *optarg;
    int ch;

    opterr = 1;

    while ((ch = getopt (ac, av, "vxl:q:f:s:S")) != EOF)
      switch (ch)
	{
	case 'v':
          if (!log_is_enabled_info)
            (void)log_set_level(LOG_LEVEL_INFO);
	  break;
	case 'x':
          (void)log_set_level(LOG_LEVEL_DEBUG);
	  break;
	case 'l':
          if (log_set_destination(optarg)) {
              log_syserr("Couldn't set logging destination to \"%s\"",
                      optarg);
              exit(1);
          }
	  break;
	case 'q':
	  pqfname = optarg;
	  break;
	case 's':
	  seq_start = atoi (optarg);
	  break;
	case 'f':
	  feedtype = atofeedtypet (optarg);
	  if (feedtype == NONE)
	    {
	      fprintf (stderr, "Unknown feedtype \"%s\"\n", optarg);
	      usage (progname);
	    }
	  break;
	case 'S':
	     statusoff=1;
	     break;
	case '?':
	  usage (progname);
	  break;
	}

    setQueuePath(pqfname);

    ac -= optind;
    av += optind;

    if (ac < 1)
      usage (progname);
  }

  /*
   * register exit handler
   */
  if (atexit (cleanup) != 0)
    {
      log_syserr ("atexit");
      exit (1);
    }

  /*
   * set up signal handlers
   */
  set_sigactions ();

  /*
   * who am i, anyway
   */
  (void) strcpy (myname, ghostname ());

  /*
   * open the product queue
   */
  if ((status = pq_open (pqfname, PQ_DEFAULT, &pq)))
    {
      if (status > 0) {
          log_add_syserr("\"%s\" failed", pqfname);
          log_flush_error();
      }
      else {
          log_error_q("\"%s\" failed: %s", pqfname, "Internal error");
      }
      exit (2);
    }


  {
    char *filename;
    int fd;
    struct stat statb;
    product prod;
    unsigned char *prodmmap;
    MD5_CTX *md5ctxp = NULL;
    int gversion;

    /*
     * Allocate an MD5 context
     */
    md5ctxp = new_MD5_CTX ();
    if (md5ctxp == NULL)
      {
	log_syserr ("new_md5_CTX failed");
	exit (6);
      }

    /* These members are constant over the loop. */
    prod.info.origin = myname;
    prod.info.feedtype = feedtype;

    prod.info.seqno = seq_start;

    /*
     * Open the file to be inserted and process
     */
    while (ac > 0)
      {
        long insert_sum = 0;
	long sinfo_cnt = 0;
        long stat_size = 0;

	filename = *av;
	av++;
	ac--;

	log_notice_q ("open and memorymap %s\0", filename);

	fd = open (filename, O_RDONLY, 0);
	if (fd == -1)
	  {
	    log_syserr ("open: %s", filename);
	    continue;
	  }

	if (fstat (fd, &statb) == -1)
	  {
	    log_syserr ("fstat: %s", filename);
	    (void) close (fd);
	    continue;
	  }

	if ((prodmmap = (unsigned char *) mmap (0, statb.st_size,
				       PROT_READ, MAP_PRIVATE, fd,
				       0)) == MAP_FAILED)
	  {
	    log_syserr ("allocation failed");
	  }
	else
	  {
	    int GRIBDONE = 0;
	    off_t griboff = 0;
	    size_t griblen = 0;
	    log_notice_q ("%ld bytes memory mapped\0", (long) statb.st_size);

	    while (!GRIBDONE)
	      {
		log_debug("griboff %d\0", (int) griboff);
		/* get offset of next grib product */
		status =
		  get_grib_info (prodmmap, statb.st_size, &griboff, &griblen,
				 &gversion);

		switch (status)
		  {
		  case 0:
		    prod.data = prodmmap + griboff;
		    prod.info.sz = griblen;

		    /*
		     * revised MD5 calculation...using filename
		     * to allow duplicate products in different files.
		     */
		    MD5Init (md5ctxp);
  		    MD5Update (md5ctxp, (void *)filename, strlen(filename));
  		    /*MD5Update (md5ctxp, (void *)prod.data, prod.info.sz);*/
		    if ( prod.info.sz > 10000 )
  		       MD5Update (md5ctxp, (void *)prod.data, 10000);
		    else
  		       MD5Update (md5ctxp, (void *)prod.data, prod.info.sz);
  		    MD5Final (prod.info.signature, md5ctxp);

		    /*if (mm_md5 (md5ctxp, prod.data, prod.info.sz,
				prod.info.signature) != 0)
		      {
			log_error_q ("could not compute MD5\0");
		      }
		    else
		      { */
			prod.info.ident = (char *) malloc (KEYSIZE + 1);
			get_gribname (gversion, prod.data, prod.info.sz,
				      filename, prod.info.seqno,
				      prod.info.ident);
			/*
			 * Do the deed
			 */
			status = set_timestamp (&prod.info.arrival);
			if (status != ENOERR)
			  {
			    log_add_syserr("could not set timestamp");
                            log_flush_error();
			  }
			/*
			 * Insert the product
			 */
			status = pq_insert (pq, &prod);
			log_info_q ("%d %s\0", status, prod.info.ident);
                
			if ( status == ENOERR )
			   insert_sum += prod.info.sz;

			if (! statusoff )
			  {
			  /*
			   * Log this status
			   */
			    sinfo_cnt++;
			    sinfo = (stat_info *)malloc(sizeof(stat_info));
                   	    sinfo->insertstatus = status;
			    sinfo->prodname = (char *)malloc(strlen(prod.info.ident)+1);
                   	    strcpy(sinfo->prodname, prod.info.ident);
                   	    sinfo->seqno = prod.info.seqno;
                   	    sinfo->prodsz = prod.info.sz;
                   	    sinfo->next = NULL;
                   	    stat_size += strlen(sinfo->prodname);
                   	    if(shead == NULL)
			      {
                      	        shead = sinfo;
                      	        slast = sinfo;
                   	      }
                   	    else 
			      {
                      	        slast->next = sinfo;
                      	        slast = sinfo;
                   	      }
			  }
		      /*}*/
		    griboff += griblen;
		    prod.info.seqno++;
		    break;
		  case -1:
		    GRIBDONE = 1;
		    break;
		  case -2:
		    log_error_q ("truncated grib file at: %d", prod.info.seqno);
		    GRIBDONE = 1;
		    break;
		  case -7:
		    log_error_q ("End sequence 7777 not found where expected: %d",
			    prod.info.seqno);
		    griboff += griblen;
		    log_error_q("resume looking at %d\0",griboff);
		    break;
		  default:
		    log_error_q ("unknown error %d\0", status);
		    griboff += griblen;
		    if (griboff >= statb.st_size)
		      GRIBDONE = 1;
		    break;
		  }

		if (griboff >= statb.st_size)
		  GRIBDONE = 1;
	      }


	    log_notice_q ("munmap\0");
	    (void) munmap ((void *)prodmmap, statb.st_size);

	    if ( stat_size != 0 )
	    /*
	     * Add a status message to product queue
	     */
	      {
		char *statusmess;
		log_notice_q("stats_size %ld %ld\0",stat_size,sinfo_cnt);

		statusmess = calloc((30 * sinfo_cnt) + stat_size +
                        strlen(filename) + 128, sizeof(char));
                if(statusmess == NULL) 
		  {
              	    log_syserr("could not malloc status message %ld\0",
              	            stat_size);
           	  }
           	else
		  {
		    char tmpprod[512];
                    sinfo = shead; slast = NULL;

                    status = set_timestamp(&prod.info.arrival);
                    /* ctime ends with \n\0" */
                    sprintf(statusmess,"%s complete (%ld bytes) at %sInserted %ld of %ld\n",
                       filename,(long)statb.st_size, ctime(&prod.info.arrival.tv_sec),
                       insert_sum,(long)statb.st_size);

                    while(sinfo != NULL) 
		      {
                        sprintf(tmpprod,"%3d %5d %8d %s\n",sinfo->insertstatus,
                            sinfo->seqno,sinfo->prodsz,sinfo->prodname);
                        strcat(statusmess,tmpprod);

                        slast = sinfo;
                 	sinfo = sinfo->next;

                        free(slast->prodname);
                    	free(slast);

                      }

		    shead = NULL;

                    sprintf(tmpprod,".status.%s %06d",filename, prod.info.seqno);
                    prod.info.ident = tmpprod;
                    prod.data = statusmess;
                    prod.info.sz = strlen(statusmess);
                    status = mm_md5(md5ctxp, prod.data, prod.info.sz, prod.info.signature);
                    status = set_timestamp(&prod.info.arrival);
                    status = pq_insert(pq, &prod);
                    if(log_is_enabled_info)
                        log_info_q("%s", s_prod_info(NULL, 0, &prod.info,
                                log_is_enabled_debug)) ;
                    free(statusmess);
		    prod.info.seqno++;
		  }
	      }
	  }

	(void) close (fd);
      }
  }

exit(0);
}
Beispiel #22
0
int
main(int ac, char *av[])
{
        int logfd;
        int width;
        int ready;
        unsigned long idle;
        fd_set readfds;
        fd_set exceptfds;
        struct timeval timeo;
        const char* const progname = basename(av[0]);
        unsigned long maxProductSize = DEFAULT_MAX_PRODUCT_SIZE;

        /*
         * Setup default logging before anything else.
         */
        (void)log_init(progname);

        feedtype = whatami(av[0]);

        {
            extern int optind;
            extern int opterr;
            extern char *optarg;
            int ch;

            opterr = 0; /* stops getopt() from printing to stderr */
            usePil = 1;
            useNex = 1;

            while ((ch = getopt(ac, av, ":vxcni5Nl:b:p:P:T:q:r:f:s:")) != EOF)
                    switch (ch) {
                    case 'v':
                            if (!log_is_enabled_info)
                                (void)log_set_level(LOG_LEVEL_INFO);
                            break;
                    case 'x':
                            (void)log_set_level(LOG_LEVEL_DEBUG);
                            break;
                    case 'c':
                            chkflag = CHK_CHECK;
                            break;
                    case 'n':
                            chkflag = CHK_DONT;
                            break;
                    case 'i':
                            usePil = 0;
                            break;
                    case 'N':
                            useNex = 0;
                            break;
                    case '5':
                            skipLeadingCtlString = 0;
                            break;
                    case 'l': {
                            (void)log_set_destination(optarg);
                            break;
                    }
                    case 'b':
                            baud = optarg;
                            break;
                    case 'p':
                            parity = optarg;
                            break;
    #if NET
                    case 'P':
                            *((int *)&server_port) = atoi(optarg); /* cast away const */
                            if(server_port <= 0 || server_port > 65536)
                            {
                                    log_error("Invalid server port: \"%s\"", optarg);
                                    usage(progname);
                            }
                            break;
                    case 'T':
                            reset_secs = atoi(optarg);
                            if(reset_secs < 0)
                            {
                                    log_add("Invalid timeout: \"%s\"", optarg);
                                    usage(progname);
                            }
                            break;
    #endif /* NET */
                    case 's': {
                            unsigned long size;
                            int           nbytes;

                            if (sscanf(optarg, "%lu %n", &size, &nbytes) != 1 ||
                                    optarg[nbytes] != 0 || 1 > size) {
                                log_error("Invalid maximum data-product size: \"%s\"",
                                        optarg);
                                usage(progname);
                            }

                            maxProductSize = size;
                            break;
                    }
                    case 'q':
                            setQueuePath(optarg);
                            break;
                    case 'r':
                            rawfname = optarg;
                            break;
                    case 'f':
                            {
                                    feedtypet type;
                                    type = atofeedtypet(optarg);
                                    if(type != NONE)
                                    {
                                            feedtype = type;
                                            if(!parity && !baud)
                                                    setFeedDefaults(type);
                                    }
                            }
                            break;
                    case '?': {
                            log_add("Unknown option: \"%c\"", optopt);
                            usage(progname);
                            break;
                    }
                    case ':':
                    /*FALLTHROUGH*/
                    default:
                            log_add("Missing argument for option: \"%c\"", optopt);
                            usage(progname);
                            break;
                    }

            /* last arg, feedfname, is required */
            if(ac - optind != 1) {
                    log_add("Wrong number of operands: %d", ac - optind);
                    usage(progname);
            }
            (void)strncat(feedfname, av[optind], sizeof(feedfname)-6);
        }

        pqpath = getQueuePath();

        log_notice("Starting Up");
        log_debug(PACKAGE_VERSION);

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr("atexit");
                return 1;
        }

        /*
         * set up signal handlers
         */
        set_sigactions();

        /*
         * open the product queue, unless we were invoked as "feedtest"
         */
        if(strcmp(progname, "feedtest") != 0)
        {
                if((ready = pq_open(pqpath, PQ_DEFAULT, &pq)))
                {
                        if (PQ_CORRUPT == ready) {
                            log_error("The product-queue \"%s\" is inconsistent\n",
                                    pqpath);
                        }
                        else {
                            log_error("pq_open: \"%s\" failed: %s",
                                    pqpath, strerror(ready));
                        }
                        return 1;
                }
        }

        /*
         * who am i, anyway
         */
        (void) strncpy(myname, ghostname(), sizeof(myname));
        myname[sizeof(myname)-1] = 0;

        /*
         * open the feed
         */
        if(!(*feedfname == '-' && feedfname[1] == 0) && logfd != 0)
                (void) close(0);

        if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR)
                return 1;

        if(usePil == 1)
           {
           if ((feedtype & DDS)||(feedtype & PPS)||(feedtype & IDS)||
                (feedtype & HRS))
              {
              usePil = 1;
              log_info("Creating AFOS-like pil tags\0");
              }
           else
              {
              usePil = 0;
              }
           }

        if (feedtype & HDS)
        {
                if(chkflag == CHK_CHECK
                                || (isatty(ifd) && chkflag != CHK_DONT))
                        setTheScanner(scan_wmo_binary_crc);
                else
                        setTheScanner(scan_wmo_binary);
        }
        else if (feedtype == ( DDPLUS | IDS ) ) 
        { 
                /* this is the combined NOAAPORT fos-alike. We know these have the
                   4 byte start and end sequences. Using the binary scanner
                   ensures that we don't stop on an arbitray embedded CTRL-C */
                log_notice("Note: Using the wmo_binary scanner for SDI ingest\0");
                setTheScanner (scan_wmo_binary); 
        }
        else if (feedtype & (NMC2 | NMC3))
        {
                setTheScanner(scan_wmo_binary);
        }
        else if (feedtype == AFOS)
        {
                prod_stats = afos_stats;
                setTheScanner(scan_afos);
        }
        else if (feedtype == FAA604)
        {
                prod_stats = faa604_stats;
                if(chkflag == CHK_CHECK
                        || (isatty(ifd)
                                 && chkflag != CHK_DONT
                                 && parity != NULL
                                 && *parity != 'n')
                        )
                {
                        setTheScanner(scan_faa604_parity);
                }
                else
                {
                        setTheScanner(scan_faa604);
                }
        }
        else
        {
                if(chkflag == CHK_CHECK
                        || (isatty(ifd)
                                 && chkflag != CHK_DONT
                                 && parity != NULL
                                 && *parity != 'n')
                        )
                {
                        setTheScanner(scan_wmo_parity);
                }
                else
                {
                        setTheScanner(scan_wmo);
                }
        }

        /*
         * Allocate an MD5 context
         */
        md5ctxp = new_MD5_CTX();
        if(md5ctxp == NULL)
        {
                log_syserr("new_md5_CTX failed");
                return 1;
        }


        /*
         * Main Loop
         */
        idle = 0;
        while(exitIfDone(0))
        {
#if NET
if (INPUT_IS_SOCKET)
{
                if (port_error)
                {
                        /*
                         * lost connection => close
                         */
                        if (ifd >= 0)
                        {
                                if(feed_close)
                                        (*feed_close)(ifd);
                                ifd = -1;
                        }
                        port_error = 0;
                        sleep (2);      /* allow things to settle down */
                        continue;
                }
}
#endif
                if(stats_req)
                {
                        log_notice("Statistics Request");
                        if(pq != NULL)
                        {
                                off_t highwater = 0;
                                size_t maxregions = 0;
                                (void) pq_highwater(pq, &highwater,
                                         &maxregions);
                                log_notice("  Queue usage (bytes):%8ld",
                                                        (long)highwater);
                                log_notice("           (nregions):%8ld",
                                                        (long)maxregions);
                        }
                        log_notice("       Idle: %8lu seconds", idle);
#if NET
if (INPUT_IS_SOCKET)
{
                        log_notice("    Timeout: %8d", reset_secs);
}
#endif
                        log_notice("%21s: %s", "Status",
                                (ifd < 0) ?
                                "Not connected or input not open." :
                                "Connected.");
                        (*prod_stats)();
                        (*feed_stats)();
                        stats_req = 0;
                }
#if NET
if (INPUT_IS_SOCKET)
{
                if (ifd < 0)
                {
                        /* Attempt reconnect */
                        static int retries = 0;
                        if (retries > MAX_RETRIES)
                        {
                                log_error ("maximum retry attempts %d, aborting",
                                        MAX_RETRIES);
                                done = !0;
                                continue;
                        }
                        /* Try to reopen on tcp read errors */
                        log_notice("Trying to re-open connection on port %d",
                                server_port);
                        ++retries;
                        if(open_feed(feedfname, &ifd, maxProductSize) != ENOERR)
                        {
                                log_notice ("sleeping %d seconds before retry %d",
                                         retries * RETRY_DELAY, retries+1);
                                sleep (retries * RETRY_DELAY);
                                continue;
                        }
                        retries = 0;
                }
}
#endif /* NET */
                timeo.tv_sec = 3;
                timeo.tv_usec = 0;
                FD_ZERO(&readfds);
                FD_ZERO(&exceptfds);
                FD_SET(ifd, &readfds);
                FD_SET(ifd, &exceptfds);
                width =  ifd + 1;
                ready = select(width, &readfds, 0, &exceptfds, &timeo);
                if(ready < 0 )
                {
                        /* handle EINTR as a special case */
                        if(errno == EINTR)
                        {
                                errno = 0;
                                continue;
                        }
                        log_syserr("select");
                        return 1;
                }
                /* else */
#if 0
                if (FD_ISSET(ifd, &exceptfds))
                {
                        log_error("Exception on input fd %d, select returned %d",
                               ifd, ready);
                }
#endif
                if(ready > 0)
                {
                        /* do some work */
                        if(FD_ISSET(ifd, &readfds) || 
                           FD_ISSET(ifd, &exceptfds))
                        {
                                idle = 0;
                                if(feedTheXbuf(ifd) != ENOERR)
                                {
#if NET
if (INPUT_IS_SOCKET)
{
                                        port_error = !0;
                                        continue;
}                                       /* else */
#endif /* NET */
                                        done = !0;
                                }
                                FD_CLR(ifd, &readfds);
                                FD_CLR(ifd, &exceptfds);
                        }
                        else
                        {
                                log_error("select returned %d but ifd not set",
                                        ready);
                                idle += timeo.tv_sec;
                        }
                }
                else    /* ready == 0 */
                {
                        idle += timeo.tv_sec;
#if NET
if (INPUT_IS_SOCKET)
{
                        /* VOODOO
                         * This is necessary to stimulate
                         * 'Connection reset by peer'
                         * when the Portmaster goes down and comes
                         * back up.
                         */
                        static char zed[1] = {0};
                        if(write(ifd, zed, sizeof(zed)) < 0)
                        {
                                port_error = !0;
                                continue;
                        }

}
#endif
                }
#if NET
if (INPUT_IS_SOCKET)
{
                if ((reset_secs > 0) && (idle >= reset_secs))
                {
                        log_notice("Idle for %ld seconds, reconnecting",
                                idle);
                        /* force reconnect */
                        port_error = !0;
                        idle = 0;
                        continue;
                }
}
#endif /* NET */
                (void) scanTheXbuf();
        }

        return 0;
}
Beispiel #23
0
int main(int ac, char *av[])
{
        unsigned      timeo = DEFAULT_TIMEO;
        unsigned      interval = DEFAULT_TIMEO;
        unsigned      TotalTimeo = DEFAULT_TOTALTIMEO;
        prod_spec     spec;
        int           status;
        prod_class_t* clssp;

        /*
         * initialize logger
         */
        if (log_init(av[0])) {
            log_syserr("Couldn't initialize logging module");
            exit(1);
        }

        if(set_timestamp(&clss.from) != 0)
        {
                fprintf(stderr, "Couldn't set timestamp\n");
                exit(1);
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;
        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        { /* Begin getopt block */
        extern int optind;
        extern int opterr;
        extern char *optarg;
        int ch;
        int fterr;

        opterr = 1;

        while ((ch = getopt(ac, av, "vxl:f:o:t:h:P:p:T:")) != EOF)
                switch (ch) {
                case 'v':
                        if (!log_is_enabled_info)
                            log_set_level(LOG_LEVEL_INFO);
                        break;
                case 'x':
                        log_set_level(LOG_LEVEL_DEBUG);
                        break;
                case 'l':
                        if (log_set_destination(optarg)) {
                            log_syserr("Couldn't set logging destination to \"%s\"",
                                    optarg);
                            usage(av[0]);
                        }
                        break;
                case 'h':
                        remote = optarg;
                        break;
                case 'P': {
                    log_warning("Port specification is ignored");
                    break;
                }
                case 'p':
                        spec.pattern = optarg;
                        /* compiled below */
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                fprintf(stderr, "Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(av[0]);   
                        }
                        break;
                case 'o':
                        clss.from.tv_sec -= atoi(optarg);
                        break;
                case 'T':
                        TotalTimeo = atoi(optarg);
                        if(TotalTimeo == 0)
                        {
                                fprintf(stderr, "%s: invalid TotalTimeo %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case 't':
                        timeo = (unsigned)atoi(optarg);
                        if(timeo == 0 || timeo > 32767)
                        {
                                fprintf(stderr, "%s: invalid timeout %s", av[0], optarg);
                                usage(av[0]);   
                        }
                        break;
                case '?':
                        usage(av[0]);
                        break;
                }

        if(ac - optind > 0)
                usage(av[0]);

        if (re_isPathological(spec.pattern))
        {
                fprintf(stderr, "Adjusting pathological regular-expression: "
                    "\"%s\"\n", spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx,
                spec.pattern,
                REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                fprintf(stderr, "Bad regular expression \"%s\"\n",
                        spec.pattern);
                usage(av[0]);
        }

        if(TotalTimeo < timeo)
        {
                fprintf(stderr, "TotalTimeo %u < timeo %u\n",
                         TotalTimeo, timeo);
                usage(av[0]);
        }

        } /* End getopt block */

        log_notice_q("Starting Up: %s: %s",
                        remote,
                        s_prod_class(NULL, 0, &clss));

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr("atexit");
                exit(1);
        }

        /*
         * set up signal handlers
         */
        set_sigactions();


        /*
         * Try forever.
         */
        while (exitIfDone(0))
        {
                clssp = &clss;
                status = forn5(NOTIFYME, remote, &clssp,
                                timeo, TotalTimeo, notifymeprog_5);

                (void)exitIfDone(0);

                switch(status) {
                        /* problems with remote, retry */       
                case ECONNABORTED:
                case ECONNRESET:
                case ETIMEDOUT:
                case ECONNREFUSED:
                        sleep(interval);
                        break;
                case 0:
                        /* assert(done); */
                        break;
                default:
                        /* some wierd error */
                        done = 1;
                        exit(1);
                }
        }

        exit(0);
        /*NOTREACHED*/
}
Beispiel #24
0
int
main(int ac, char *av[])
{
        int          status = 0;
        char*        logfname = 0;
        /// Data directory, conffile paths may be relative
        const char*  datadir;
        int          interval = DEFAULT_INTERVAL;
        prod_spec    spec;
        prod_class_t clss;
        int          toffset = TOFFSET_NONE;
        int          loggingToStdErr = 0;
        unsigned     queue_size = 5000;
        const char*  progname = basename(av[0]);
        unsigned     logopts = LOG_CONS|LOG_PID;

        /*
         * Setup default logging before anything else.
         */
        (void)log_init(progname);

        const char*  pqfname = getQueuePath();

        spec.feedtype = DEFAULT_FEEDTYPE;
        spec.pattern = DEFAULT_PATTERN;

        if(set_timestamp(&clss.from)) /* corrected by toffset below */
        {
                int errnum = errno;
                log_error("Couldn't set timestamp: %s", strerror(errnum));
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        clss.to = TS_ENDT;
        clss.psa.psa_len = 1;
        clss.psa.psa_val = &spec;

        /*
         * deal with the command line, set options
         */
        {
            extern int optind;
            extern int opterr;
            extern char *optarg;

            int ch;
            int fterr;

            opterr = 1;

            while ((ch = getopt(ac, av, "vxel:d:f:q:o:p:i:t:")) != EOF) {
                switch (ch) {
                case 'v':
                        if (!log_is_enabled_info)
                            (void)log_set_level(LOG_LEVEL_INFO);
                        break;
                case 'x':
                        (void)log_set_level(LOG_LEVEL_DEBUG);
                        break;
                case 'e':
                        key = ftok("/etc/rc.d/rc.local",'R');
                        semkey = ftok("/etc/rc.d/rc.local",'e');
                        shmid = shmget(key, sizeof(edex_message) * queue_size,
                                0666 | IPC_CREAT);
                        semid = semget(semkey, 2, 0666 | IPC_CREAT);
                        break;
                case 'l':
                        logfname = optarg;
                        (void)log_set_destination(logfname);
                        break;
                case 'd':
                        setPqactDataDirPath(optarg);
                        break;
                case 'f':
                        fterr = strfeedtypet(optarg, &spec.feedtype);
                        if(fterr != FEEDTYPE_OK)
                        {
                                log_error("Bad feedtype \"%s\", %s\n",
                                        optarg, strfeederr(fterr));
                                usage(progname);
                        }
                        break;
                case 'q':
                        pqfname = optarg;
                        break;
                case 'o':
                        toffset = atoi(optarg);
                        if(toffset == 0 && *optarg != '0')
                        {
                                log_error("invalid offset %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 'i':
                        interval = atoi(optarg);
                        if(interval == 0 && *optarg != '0')
                        {
                                log_error("invalid interval %s\n", optarg);
                                usage(progname);   
                        }
                        break;
                case 't':
                        pipe_timeo = atoi(optarg);
                        if(pipe_timeo == 0 && *optarg != 0)
                        {
                                log_error("invalid pipe_timeo %s", optarg);
                                usage(progname);   
                        }
                        break;
                case 'p':
                        spec.pattern = optarg;
                        break;
                default:
                        usage(progname);
                        break;
                }
            }

            conffilename = getPqactConfigPath();
            datadir = getPqactDataDirPath();

            {
                int numOperands = ac - optind;

                if (1 < numOperands) {
                    log_error("Too many operands");
                    usage(progname);
                }
                else if (1 == numOperands) {
                    conffilename = av[optind];
                }
            }
        }

        setQueuePath(pqfname);
        log_notice("Starting Up");

        if ('/' != conffilename[0]) {
            /*
             * The pathname of the configuration-file is relative. Convert it
             * to absolute so that it can be (re)read even if the current
             * working directory changes.
             */
#ifdef PATH_MAX
            char    buf[PATH_MAX];          /* includes NUL */
#else
            char    buf[_POSIX_PATH_MAX];   /* includes NUL */
#endif
            if (getcwd(buf, sizeof(buf)) == NULL) {
                log_syserr("Couldn't get current working directory");
                exit(EXIT_FAILURE);
            }
            (void)strncat(buf, "/", sizeof(buf)-strlen(buf)-1);
            (void)strncat(buf, conffilename, sizeof(buf)-strlen(buf)-1);
            conffilename = strdup(buf);
            if (conffilename == NULL) {
                log_syserr("Couldn't duplicate string \"%s\"", buf);
                exit(EXIT_FAILURE);
            }
        }

        /*
         * Initialize the previous-state module for this process.
         */
        if (stateInit(conffilename) < 0) {
            log_error("Couldn't initialize previous-state module");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Configure the standard I/O streams for execution of child processes.
         */
        if (configure_stdio_file_descriptors()) {
            log_error("Couldn't configure standard I/O streams for execution "
                    "of child processes");
            exit(EXIT_FAILURE);
        }

        /*
         * Inform the "filel" module about the number of available file
         * descriptors.  File descriptors are reserved for stdin, stdout,
         * stderr, the product-queue, the configuration-file, and (possibly) 
         * logging.
         */
        if (0 != set_avail_fd_count(openMax() - 6))
        {
            log_error("Couldn't set number of available file-descriptors");
            log_notice("Exiting");
            exit(EXIT_FAILURE);
            /*NOTREACHED*/
        }

        /*
         * Inform the "filel" module of the shared memory segment
         */
        if (shmid != -1 && semid != -1)
        {
            set_shared_space(shmid, semid, queue_size);
        }

        /*
         * Compile the pattern.
         */
        if (re_isPathological(spec.pattern))
        {
                log_error("Adjusting pathological regular-expression: \"%s\"",
                    spec.pattern);
                re_vetSpec(spec.pattern);
        }
        status = regcomp(&spec.rgx, spec.pattern, REG_EXTENDED|REG_NOSUB);
        if(status != 0)
        {
                log_error("Can't compile regular expression \"%s\"",
                        spec.pattern);
                log_notice("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        /*
         * register exit handler
         */
        if(atexit(cleanup) != 0)
        {
                log_syserr("atexit");
                log_notice("Exiting");
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        /*
         * set up signal handlers
         */
        set_sigactions();

        /*
         * Read in (compile) the configuration file.  We do this first so
         * its syntax may be checked without opening a product queue.
         */
        if ((status = readPatFile(conffilename)) < 0) {
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }
        else if (status == 0) {
            log_notice("Configuration-file \"%s\" has no entries. "
                "You should probably not start this program instead.",
                conffilename);
        }

        /*
         * Open the product queue
         */
        status = pq_open(pqfname, PQ_READONLY, &pq);
        if(status)
        {
                if (PQ_CORRUPT == status) {
                    log_error("The product-queue \"%s\" is inconsistent\n",
                            pqfname);
                }
                else {
                    log_error("pq_open failed: %s: %s\n",
                            pqfname, strerror(status));
                }
                exit(EXIT_FAILURE);
                /*NOTREACHED*/
        }

        if(toffset != TOFFSET_NONE) {
            /*
             * Filter and queue position set by "toffset".
             */
            clss.from.tv_sec -= toffset;
            pq_cset(pq, &clss.from);
        }
        else {
            bool       startAtTailEnd = true;
            timestampt insertTime;

            clss.from = TS_ZERO;

            /*
             * Try getting the insertion-time of the last,
             * successfully-processed data-product from the previous session.
             */
            status = stateRead(&insertTime);

            if (status) {
                log_warning("Couldn't get insertion-time of last-processed "
                        "data-product from previous session");
            }
            else {
                timestampt now;
                (void)set_timestamp(&now);

                if (tvCmp(now, insertTime, <)) {
                    log_warning("Time of last-processed data-product from previous "
                            "session is in the future");
                }
                else {
                    char buf[80];
                    (void)strftime(buf, sizeof(buf), "%Y-%m-%d %T",
                        gmtime(&insertTime.tv_sec));
                    log_notice("Starting from insertion-time %s.%06lu UTC", buf,
                        (unsigned long)insertTime.tv_usec);

                    pq_cset(pq, &insertTime);
                    startAtTailEnd = false;
                }
            }

            if (startAtTailEnd) {
                log_notice("Starting at tail-end of product-queue");
                (void)pq_last(pq, &clss, NULL);
            }
        }