int main(int argc, char *argv[])
{
	pid_t pid;
    const char *pcFD_GPIO   = NULL;
    const char *pcI2Cbus    = NULL;
    uint8_t     u8I2CAddress = 0;
    const char *pcPWR_GPIO  = NULL;
    
    {
        static struct option long_options[] =
        {
            /* Program options */
            {"help",                    no_argument,        NULL, 'h'},
            {"foreground",              no_argument,        NULL, 'f'},
            {"verbosity",               required_argument,  NULL, 'v'},
            
            {"gpio-fd",                 required_argument,  NULL, 0},
            {"i2c-bus",                 required_argument,  NULL, 1},
            {"i2c-address",             required_argument,  NULL, 2},
            {"gpio-pwr",                required_argument,  NULL, 3},

            { NULL, 0, NULL, 0}
        };
        signed char opt;
        int option_index;

        while ((opt = getopt_long(argc, argv, "hfv:", long_options, &option_index)) != -1) 
        {
            switch (opt) 
            {
                case 'h':
                    print_usage_exit(argv);
                    break;
                case 'f':
                    daemonize = 0;
                    break;
                case 'v':
                    verbosity = atoi(optarg);
                    break;
                
                case 0:
                    pcFD_GPIO = optarg;
                    break;
                    
                case 1:
                    pcI2Cbus = optarg;
                    break;
                    
                case 2:
                {
                    char *pcEnd;
                    errno = 0;
                    uint32_t u32I2CAddress = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        fprintf(stderr, "I2C Address '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        fprintf(stderr, "I2C Address '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    if (u32I2CAddress > 0x7F)
                    {
                        fprintf(stderr, "I2C Address '%s' outside allowable range (0x01 - 0x7F)\n", optarg);
                        print_usage_exit(argv);
                    }
                    u8I2CAddress = u32I2CAddress;
                    break;
                }
                
                case 3:
                    pcPWR_GPIO = optarg;
                    break;
                    
                default: /* '?' */
                    print_usage_exit(argv);
            }
        }
    }
    
    if (!pcFD_GPIO)
    {
        fprintf(stderr, "GPIO for field detect pin must be specified\n");
        print_usage_exit(argv);
    }
    
    if (!pcI2Cbus)
    {
        fprintf(stderr, "I2C bus must be specified\n");
        print_usage_exit(argv);
    }
    
    if (!u8I2CAddress)
    {
        fprintf(stderr, "I2C address must be specified\n");
        print_usage_exit(argv);
    }
    
    /* Log everything into syslog */
    daemon_log_ident = daemon_ident_from_argv0(argv[0]);
    
    if (daemonize)
    {
        /* Prepare for return value passing from the initialization procedure of the daemon process */
        if (daemon_retval_init() < 0) {
            daemon_log(LOG_ERR, "Failed to create pipe.");
            return 1;
        }

        /* Do the fork */
        if ((pid = daemon_fork()) < 0)
        {
            /* Exit on error */
            daemon_log(LOG_ERR, "Failed to fork() daemon process.");
            daemon_retval_done();
            return 1;
        } 
        else if (pid)
        { /* The parent */
            int ret;

            /* Wait for 20 seconds for the return value passed from the daemon process */
            if ((ret = daemon_retval_wait(20)) < 0)
            {
                daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
                return 255;
            }

            if (ret == 0)
            {
                daemon_log(LOG_INFO, "Daemon process started.");
            }
            else
            {
                daemon_log(LOG_ERR, "Daemon returned %i.", ret);
            }
            return ret;
        } 
        else
        { /* The daemon */
            /* Close FDs */
            if (daemon_close_all(-1) < 0)
            {
                daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));

                /* Send the error condition to the parent process */
                daemon_retval_send(1);
                goto finish;
            }

            daemon_log_use = DAEMON_LOG_SYSLOG;

            /* Send OK to parent process */
            daemon_retval_send(0);

            daemon_log(LOG_INFO, "Daemon started");
        }
    }
    else
    {
        /* Running foreground - set verbosity */
        if (verbosity > LOG_WARNING)
        {
            daemon_set_verbosity(verbosity);
        }
    }

    /* Install signal handlers */
    signal(SIGTERM, vQuitSignalHandler);
    signal(SIGINT, vQuitSignalHandler);

    if (eNtagSetup(pcPWR_GPIO, pcFD_GPIO, pcI2Cbus, u8I2CAddress) == E_NFC_OK)
    {
        if (eNdefSetup() == E_NFC_OK)
        {
            while (bRunning != 0)
            {
                if (eNtagWait(30000) == E_NFC_READER_PRESENT)
                {
                    /* Tag detected */
                    while ((eNtagPresent() == E_NFC_READER_PRESENT) && bRunning)
                    {
                        sleep(1);
                        
                        teNfcStatus eStatus = eNtagRfUnlocked();
                        
                        switch (eStatus)
                        {
                            case (E_NFC_OK):
                                vHandleTag();
                                break;
                                
                            case (E_NFC_RF_LOCKED):
                                DEBUG_PRINTF("RF Locked\n");
                                break;
                                
                            default:
                                break;
                        }
                        //usleep(100000);
                        //sleep(1);
                    }
                }
                else
                {
                    /* Blank the tag */
                    tsNdefData sData;
                    eNdefInitData(&sData, 0, 0);
                    eNdefWriteData(&sData);
                }
            }
        }
    }
    else
    {
        DEBUG_PRINTF("Failed to init NTAG\n");
    }
    
finish:
    if (daemonize)
    {
        daemon_log(LOG_INFO, "Daemon process exiting");  
    }
    return 0;
}
int main(int argc, char *argv[])
{
    fd_set rfds;
    struct timeval tv;
    int retval;
    pid_t pid;
    char *cpSerialDevice = NULL;

    {
        static struct option long_options[] =
        {
            /* Required arguments */
            {"serial",                  required_argument,  NULL, 's'},

            /* Program options */
            {"help",                    no_argument,        NULL, 'h'},
            {"foreground",              no_argument,        NULL, 'f'},
            {"verbosity",               required_argument,  NULL, 'v'},
            {"baud",                    required_argument,  NULL, 'B'},
            {"interface",               required_argument,  NULL, 'I'},
            {"reset",                   no_argument,        NULL, 'R'},
            {"confignotify",            required_argument,  NULL, 'C'},
            {"activityled",             required_argument,  NULL, 'A'},

            /* Module options */
            {"frontend",                required_argument,  NULL, 'F'},
            {"diversity",               no_argument,        NULL, 'D'},
            
            /* 6LoWPAN network options */
            {"mode",                    required_argument,  NULL, 'm'},
            {"region",                  required_argument,  NULL, 'r'},
            {"channel",                 required_argument,  NULL, 'c'},
            {"pan",                     required_argument,  NULL, 'p'},
            {"network",                 required_argument,  NULL, 'j'},
            {"profile",                 required_argument,  NULL, 'P'},
            {"prefix",                  required_argument,  NULL, '6'},

            /* Security options */
            {"key",                     required_argument,  NULL, 'k'},
            {"authscheme",              required_argument,  NULL, 'a'},
            
            /* Radius with PAP options */
            {"radiusip",                required_argument,  NULL, 'i'},
            
            { NULL, 0, NULL, 0}
        };
        signed char opt;
        int option_index;

        while ((opt = getopt_long(argc, argv, "s:hfv:B:I:RC:A:F:Dm:r:c:p:j:P:6:k:a:i:", long_options, &option_index)) != -1) 
        {
            switch (opt) 
            {
                case 'h':
                    print_usage_exit(argv);
                    break;
                case 'f':
                    daemonize = 0;
                    break;
                case 'v':
                    verbosity = atoi(optarg);
                    break;
                case 'B':
                {
                    char *pcEnd;
                    errno = 0;
                    u32BaudRate = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("Baud rate '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("Baud rate '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    break;
                }
                case 's':
                    cpSerialDevice = optarg;
                    break;
                    
                case 'C':
                {
                    struct stat sStat;
                    
                    /* Check if the given program exists and is executable */
                    if (stat(optarg, &sStat) == 0)
                    {
                        /* File stat'd ok */
                        pcConfigProgram = optarg;
                        vprConfigChanged = ConfigChangedCallback;
                    }
                    else
                    {
                        printf("Config stat notification program '%s' (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    break;
                }
                
                case 'A':
                {
                    char *pcEnd;
                    uint32_t u32ActivityLED;
                    errno = 0;
                    u32ActivityLED = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("Activity LED '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("Activity LED '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    eActivityLED = u32ActivityLED;
                    break;
                }
                
                case 'F':
                    if (strcmp(optarg, "SP") == 0)
                    {
                        eRadioFrontEnd = E_FRONTEND_STANDARD_POWER;
                    }
                    else if (strcmp(optarg, "HP") == 0)
                    {
                        eRadioFrontEnd = E_FRONTEND_HIGH_POWER;
                    }
                    else if (strcmp(optarg, "ETSI") == 0)
                    {
                        eRadioFrontEnd = E_FRONTEND_ETSI;
                    }
                    else
                    {
                        printf("Unknown mode '%s' specified. Supported modes are 'coordinator', 'router', 'commissioning'\n", optarg);
                        print_usage_exit(argv);
                    }
                    break;
                    
                case 'D':
                    iAntennaDiversity = 1;
                    break;
                    
                case 'm':
                    if (strcmp(optarg, "coordinator") == 0)
                    {
                        eModuleMode = E_MODE_COORDINATOR;
                    }
                    else if (strcmp(optarg, "router") == 0)
                    {
                        eModuleMode = E_MODE_ROUTER;
                    }
                    else if (strcmp(optarg, "commissioning") == 0)
                    {
                        eModuleMode = E_MODE_COMMISSIONING;
                    }
                    else
                    {
                        printf("Unknown mode '%s' specified. Supported modes are 'coordinator', 'router', 'commissioning'\n", optarg);
                        print_usage_exit(argv);
                    }
                    break;
                    
                case 'r':
                {
                    char *pcEnd;
                    uint32_t u32Region;
                    errno = 0;
                    u32Region = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("Region '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("Region '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    if (u32Region > E_REGION_MAX)
                    {
                        printf("Invalid region '%s' specified\n", optarg);
                        print_usage_exit(argv);
                    }
                    eRegion = (uint8_t)u32Region;
                    break;
                }
                case 'c':
                {
                    char *pcEnd;
                    uint32_t u32Channel;
                    errno = 0;
                    u32Channel = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("Channel '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("Channel '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    if ( !((u32Channel == E_CHANNEL_AUTOMATIC) ||
                          ((u32Channel >= E_CHANNEL_MINIMUM) && 
                           (u32Channel <= E_CHANNEL_MAXIMUM))))
                    {
                        printf("Invalid Channel '%s' specified\n", optarg);
                        print_usage_exit(argv);
                    }
                    eChannel = (uint8_t)u32Channel;
                    break;
                }
                case 'p':
                {
                    char *pcEnd;
                    uint32_t u32PanID;
                    errno = 0;
                    u32PanID = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("PAN ID '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("PAN ID '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    if (u32PanID > 0xFFFF)
                    {
                        printf("Invalid PAN ID '%s' specified\n", optarg);
                        print_usage_exit(argv);
                    }
                    u16PanID = (uint16_t)u32PanID;
                    break;
                }
                case 'j':
                {
                    char *pcEnd;
                    uint32_t u32JenNetID;
                    errno = 0;
                    u32JenNetID = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("JenNet ID '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("JenNet ID '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    u32UserData = u32JenNetID;
                    break;
                }
                case 'P':
                {
                    char *pcEnd;
                    uint32_t u32JenNetProfile;
                    errno = 0;
                    u32JenNetProfile = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("JenNet Profile '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("JenNet Profile '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }
                    if (u32JenNetProfile > 0xFF)
                    {
                        printf("Invalid JenNet Profile '%s' specified\n", optarg);
                        print_usage_exit(argv);
                    }
                    u8JenNetProfile = (uint8_t)u32JenNetProfile;
                    break;
                }
                case '6':
                {
                    int result;
                    struct in6_addr address;
                    
                    result = inet_pton(AF_INET6, optarg, &address);
                    if (result <= 0)
                    {
                        if (result == 0)
                        {
                            printf("Unknown host: %s\n", optarg);
                        }
                        else if (result < 0)
                        {
                            perror("inet_pton failed");
                        }
                        exit(EXIT_FAILURE);
                    }
                    else
                    {
                        u64NetworkPrefix =  ((uint64_t)address.s6_addr[0] << 56) | 
                                            ((uint64_t)address.s6_addr[1] << 48) | 
                                            ((uint64_t)address.s6_addr[2] << 40) | 
                                            ((uint64_t)address.s6_addr[3] << 32) |
                                            ((uint64_t)address.s6_addr[4] << 24) | 
                                            ((uint64_t)address.s6_addr[5] << 16) | 
                                            ((uint64_t)address.s6_addr[6] <<  8) | 
                                            ((uint64_t)address.s6_addr[7] <<  0);
                    }
                    break;
                }
                case  'I':
                    cpTunDevice = optarg;
                    break;
                    
                case  'R':
                    iResetCoordinator = 1;
                    break;
                    
                case 'k':
                {
                    int result;
                    
                    /* The network key is specified like an IPv6 address, in 8 groups of 16-bit hexadecimal values separated by colons (:) */
                    result = inet_pton(AF_INET6, optarg, &sSecurityKey);
                    if (result <= 0)
                    {
                        if (result == 0)
                        {
                            printf("Could not parse network key: %s\n", optarg);
                        }
                        else if (result < 0)
                        {
                            perror("inet_pton failed");
                        }
                        exit(EXIT_FAILURE);
                    }
                    iSecureNetwork = 1;
                    break;
                }
                
                case 'a':
                {
                    char *pcEnd;
                    uint32_t u32AuthScheme;
                    errno = 0;
                    u32AuthScheme = strtoul(optarg, &pcEnd, 0);
                    if (errno)
                    {
                        printf("Authorisation scheme '%s' cannot be converted to 32 bit integer (%s)\n", optarg, strerror(errno));
                        print_usage_exit(argv);
                    }
                    if (*pcEnd != '\0')
                    {
                        printf("Authorisation scheme '%s' contains invalid characters\n", optarg);
                        print_usage_exit(argv);
                    }

                    switch(u32AuthScheme)
                    {
                        case 0:
                            printf("Warning - no authorisation scheme selected\n");
                            eAuthScheme = u32AuthScheme;
                            break;
                            
                        case (1):
                            eAuthScheme = u32AuthScheme;
                            break;
                            
                        default:
                            printf("Unknown authorisation scheme selected (%d)\n", u32AuthScheme);
                            print_usage_exit(argv);
                            break;
                    }
                    break;
                }
                
                case 'i':
                {
                    switch(eAuthScheme)
                    {
                        case (E_AUTH_SCHEME_RADIUS_PAP):
                        {
                            int result = inet_pton(AF_INET6, optarg, &uAuthSchemeData.sRadiusPAP.sAuthServerIP);
                            if (result <= 0)
                            {
                                if (result == 0)
                                {
                                    printf("Unknown host: %s\n", optarg);
                                }
                                else if (result < 0)
                                {
                                    perror("inet_pton failed");
                                }
                                exit(EXIT_FAILURE);
                            }
                            break;
                        }
                        
                        default:
                            printf("Option '-i' is not appropriate for authorisation scheme %d\n", eAuthScheme);
                            break;
                    }
                    break;
                }
                    
                default: /* '?' */
                    print_usage_exit(argv);
            }
        }
    }
    
    /* Log everything into syslog */
    daemon_log_ident = daemon_ident_from_argv0(argv[0]);
    
    if (!cpSerialDevice)
    {
        print_usage_exit(argv);
    }
    
    if (daemonize)
    {
        /* Prepare for return value passing from the initialization procedure of the daemon process */
        if (daemon_retval_init() < 0) {
            daemon_log(LOG_ERR, "Failed to create pipe.");
            return 1;
        }

        /* Do the fork */
        if ((pid = daemon_fork()) < 0)
        {
            /* Exit on error */
            daemon_log(LOG_ERR, "Failed to fork() daemon process.");
            daemon_retval_done();
            return 1;
        } 
        else if (pid)
        { /* The parent */
            int ret;

            /* Wait for 20 seconds for the return value passed from the daemon process */
            if ((ret = daemon_retval_wait(20)) < 0)
            {
                daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
                return 255;
            }

            if (ret == 0)
            {
                daemon_log(LOG_INFO, "Daemon process started.");
            }
            else
            {
                daemon_log(LOG_ERR, "Daemon returned %i.", ret);
            }
            return ret;
        } 
        else
        { /* The daemon */
            /* Close FDs */
            if (daemon_close_all(-1) < 0)
            {
                daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));

                /* Send the error condition to the parent process */
                daemon_retval_send(1);
                goto finish;
            }

            daemon_log_use = DAEMON_LOG_SYSLOG;

            /* Send OK to parent process */
            daemon_retval_send(0);

            daemon_log(LOG_INFO, "Daemon started");
        }
    }
    else
    {
        /* Running foreground - set verbosity */
        if (verbosity > LOG_WARNING)
        {
            daemon_set_verbosity(verbosity);
        }
    }

    FD_ZERO(&rfds);
    /* Wait up to five seconds. */
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    
    if ((serial_open(cpSerialDevice, u32BaudRate) < 0) || (eTunDeviceOpen(cpTunDevice) != E_TUN_OK))
    {
        goto finish;
    }
    
    /* Install signal handlers */
    signal(SIGTERM, vQuitSignalHandler);
    signal(SIGINT, vQuitSignalHandler);
    
    eJennicModuleStart();
    
    while (bRunning)
    {
        int max_fd = 0;
        
        /* Wait up to one second each loop. */
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        
        FD_ZERO(&rfds);
        FD_SET(serial_fd, &rfds);
        if (serial_fd > max_fd)
        {
            max_fd = serial_fd;
        }
        FD_SET(tun_fd, &rfds);
        if (tun_fd > max_fd)
        {
            max_fd = tun_fd;
        }

        /* Wait for data on one either the serial port or the TUN interface. */
        retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);

        if (retval == -1)
        {
            daemon_log(LOG_ERR, "error in select(): %s", strerror(errno));
        }
        else if (retval)
        {
            int i;
            /* Got data on one of the file descriptors */
            for (i = 0; i < max_fd + 1; i++)
            {
                if (FD_ISSET(i, &rfds) && (i == serial_fd))
                {
                    if(bSL_ReadMessage(&sIncomingMsg.u8Type, &sIncomingMsg.u16Length, sizeof(sIncomingMsg.u8Message), sIncomingMsg.u8Message))
                    {
                        if (eJennicModuleProcessMessage(sIncomingMsg.u8Type, sIncomingMsg.u16Length, sIncomingMsg.u8Message) != E_MODULE_OK)
                        {
                            daemon_log(LOG_ERR, "Error communicating with border router module");
                            bRunning = FALSE;
                        }
                    }
                }
                else if (FD_ISSET(i, &rfds) && (i == tun_fd))
                {
                    if (eTunDeviceReadPacket() != E_TUN_OK)
                    {
                        daemon_log(LOG_ERR, "Error handling tun packet");
                    }
                    /* Kick the state machine to prompt the sending of a ping packet if necessary. */
                    if (eJennicModuleStateMachine(1) != E_MODULE_OK)
                    {
                        daemon_log(LOG_ERR, "Error communicating with border router module");
                        bRunning = FALSE;
                    }
                }
                else if (FD_ISSET(i, &rfds))
                {
                    daemon_log(LOG_DEBUG, "Data on unknown file desciptor (%d)", i);
                }
                else
                {
                    /* Should not get here */
                }
            }
        }
        else
        {
            /* Select timeout */
            if (eJennicModuleStateMachine(1) != E_MODULE_OK)
            {
                daemon_log(LOG_ERR, "Error communicating with border router module");
                bRunning = FALSE;
            }
        }
    }
    
    if (iResetCoordinator)
    {
        daemon_log(LOG_INFO, "Resetting Coordinator Module");    
        eJennicModuleReset();
    }
    
finish:
    if (daemonize)
    {
        daemon_log(LOG_INFO, "Daemon process exiting");  
    }
    return 0;
}
Esempio n. 3
0
int
main(int argc, char **argv)
{
	int pid, ret;
	struct sigaction new_action, old_action;
	GOptionContext *ctx;
	GError *parse_err = NULL;

	daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
	daemon_pid_file_proc = conf_pid_file_proc;
	if (conf_init() < 0)
		return EXIT_FAILURE;

	ctx = g_option_context_new("");
	g_option_context_add_main_entries(ctx, options, PACKAGE);
	g_option_context_set_summary(ctx, PACKAGE"-"VERSION GITHEAD" - mpd cron daemon");

	if (!g_option_context_parse(ctx, &argc, &argv, &parse_err)) {
		g_printerr("option parsing failed: %s\n", parse_err->message);
		g_option_context_free(ctx);
		g_error_free(parse_err);
		return EXIT_FAILURE;
	}
	g_option_context_free(ctx);

	if (optv) {
		about();
		cleanup();
		return EXIT_SUCCESS;
	}

#ifdef DAEMON_SET_VERBOSITY_AVAILABLE
	if (conf.no_daemon)
		daemon_set_verbosity(LOG_DEBUG);
#endif /* DAEMON_SET_VERBOSITY_AVAILABLE */

	/* Version to environment variable */
	g_setenv("MPDCRON_PACKAGE", PACKAGE, 1);
	g_setenv("MPDCRON_VERSION", VERSION, 1);
	g_setenv("MPDCRON_GITHEAD", GITHEAD, 1);

	/* Command line options to environment variables */
	if (conf.no_daemon)
		g_unsetenv("MCOPT_DAEMONIZE");
	else
		g_setenv("MCOPT_DAEMONIZE", "1", 1);

	/* Important! Parse configuration file before killing the daemon
	 * because the configuration file has a pidfile and killwait option.
	 */
	cfd = g_key_file_new();
	if (keyfile_load(&cfd) < 0) {
		cleanup();
		return EXIT_FAILURE;
	}

	if (optk) {
		if (daemon_pid_file_kill_wait(SIGINT, conf.killwait) < 0) {
			g_warning("Failed to kill daemon: %s", strerror(errno));
			cleanup();
			return EXIT_FAILURE;
		}
		daemon_pid_file_remove();
		cleanup();
		return EXIT_SUCCESS;
	}

	/* Logging */
	g_log_set_default_handler(log_handler, GINT_TO_POINTER(conf.no_daemon ? 5 : conf.loglevel));

	/* Signal handling */
	new_action.sa_handler = sig_cleanup;
	sigemptyset(&new_action.sa_mask);
	new_action.sa_flags = 0;

#define HANDLE_SIGNAL(sig)					\
	do {							\
		sigaction((sig), NULL, &old_action);		\
		if (old_action.sa_handler != SIG_IGN)		\
			sigaction((sig), &new_action, NULL);	\
	} while (0)

	HANDLE_SIGNAL(SIGABRT);
	HANDLE_SIGNAL(SIGSEGV);
	HANDLE_SIGNAL(SIGINT);
	HANDLE_SIGNAL(SIGTERM);

#undef HANDLE_SIGNAL

	if (conf.no_daemon) {
		/* Create the main loop */
		loop = g_main_loop_new(NULL, FALSE);

#ifdef HAVE_GMODULE
		/* Load modules which may add initial events */
		keyfile_load_modules(&cfd);
#endif /* HAVE_GMODULE */
		g_key_file_free(cfd);
		cfd = NULL;

		/* Add default initial events */
		loop_connect();

		/* Run the main loop */
		g_main_loop_run(loop);
		cleanup();
		return EXIT_SUCCESS;
	}

	/* Daemonize */
	if ((pid = daemon_pid_file_is_running()) > 0) {
		g_critical("Daemon already running on PID %u", pid);
		return EXIT_FAILURE;
	}

	daemon_retval_init();
	pid = daemon_fork();
	if (pid < 0) {
		g_critical("Failed to fork: %s", strerror(errno));
		daemon_retval_done();
		return EXIT_FAILURE;
	}
	else if (pid != 0) { /* Parent */
		cleanup();

		if ((ret = daemon_retval_wait(2)) < 0) {
			g_critical("Could not receive return value from daemon process: %s",
				strerror(errno));
			return 255;
		}

		if (ret != 0)
			g_critical("Daemon returned %i as return value", ret);
		else
			g_critical("Daemon returned %i as return value", ret);
		return ret;
	}
	else { /* Daemon */
		if (daemon_close_all(-1) < 0) {
			g_critical("Failed to close all file descriptors: %s",
					strerror(errno));
			daemon_retval_send(1);
			return EXIT_FAILURE;
		}

		if (daemon_pid_file_create() < 0) {
			g_critical("Failed to create PID file: %s",
					strerror(errno));
			daemon_retval_send(2);
			return EXIT_FAILURE;
		}

		/* Send OK to parent process */
		daemon_retval_send(0);

		/* Create the main loop */
		loop = g_main_loop_new(NULL, FALSE);

#ifdef HAVE_GMODULE
		/* Load modules which may add initial events */
		keyfile_load_modules(&cfd);
#endif /* HAVE_GMODULE */
		g_key_file_free(cfd);
		cfd = NULL;

		/* Add default initial events */
		loop_connect();

		/* Run the main loop */
		g_main_loop_run(loop);
		cleanup();
		return EXIT_SUCCESS;
	}
	return EXIT_SUCCESS;
}