📄 motion.c
字号:
/* fork */ if (fork()) { motion_log(-1, 0, "Motion going to daemon mode"); exit(0); } /* Create the pid file if defined, if failed exit * If we fail we report it. If we succeed we postpone the log entry till * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting * for an enter. */ if (cnt_list[0]->conf.pid_file) { pidf = fopen(cnt_list[0]->conf.pid_file, "w+"); if ( pidf ) { (void)fprintf(pidf, "%d\n", getpid()); fclose(pidf); } else { motion_log(LOG_ERR, 1, "Exit motion, cannot create process id file (pid file) %s", cnt_list[0]->conf.pid_file); exit(0); } } /* changing dir to root enables people to unmount a disk without having to stop Motion */ if (chdir("/")) { motion_log(LOG_ERR, 1, "Could not change directory"); }#if (defined(BSD)) setpgrp(0, getpid());#else setpgrp();#endif /* BSD */ if ((i = open("/dev/tty", O_RDWR)) >= 0) { ioctl(i, TIOCNOTTY, NULL); close(i); } setsid(); i = open("/dev/null", O_RDONLY); if(i != -1) { dup2(i, STDIN_FILENO); close(i); } i = open("/dev/null", O_WRONLY); if(i != -1) { dup2(i, STDOUT_FILENO); dup2(i, STDERR_FILENO); close(i); } /* Now it is safe to add the PID creation to the logs */ if ( pidf ) motion_log(LOG_INFO, 0, "Created process id file %s. Process ID is %d", cnt_list[0]->conf.pid_file, getpid()); sigaction(SIGTTOU, &sig_ign_action, NULL); sigaction(SIGTTIN, &sig_ign_action, NULL); sigaction(SIGTSTP, &sig_ign_action, NULL);}/** * cntlist_create * * Sets up the 'cnt_list' variable by allocating room for (and actually * allocating) one context struct. Also loads the configuration from * the config file(s). * * Parameters: * argc - size of argv * argv - command-line options, passed initially from 'main' * * Returns: nothing */static void cntlist_create(int argc, char *argv[]){ /* cnt_list is an array of pointers to the context structures cnt for each thread. * First we reserve room for a pointer to thread 0's context structure * and a NULL pointer which indicates that end of the array of pointers to * thread context structures. */ cnt_list = mymalloc(sizeof(struct context *)*2); /* Now we reserve room for thread 0's context structure and let cnt_list[0] point to it */ cnt_list[0] = mymalloc(sizeof(struct context)); /* Populate context structure with start/default values */ context_init(cnt_list[0]); /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */ cnt_list[1] = NULL; /* Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads * the config options from motion.conf, thread config files and the command line. */ cnt_list[0]->conf.argv = argv; cnt_list[0]->conf.argc = argc; cnt_list = conf_load(cnt_list);}/** * motion_shutdown * * Responsible for performing cleanup when Motion is shut down or restarted, * including freeing memory for all the context structs as well as for the * context struct list itself. * * Parameters: none * * Returns: nothing */static void motion_shutdown(void){ int i = -1; motion_remove_pid(); while (cnt_list[++i]){ context_destroy(cnt_list[i]); } free(cnt_list);#ifndef WITHOUT_V4L vid_close(); vid_cleanup();#endif}/** * motion_startup * * Responsible for initializing stuff when Motion starts up or is restarted, * including daemon initialization and creating the context struct list. * * Parameters: * * daemonize - non-zero to do daemon init (if the config parameters says so), * or 0 to skip it * argc - size of argv * argv - command-line options, passed initially from 'main' * * Returns: nothing */static void motion_startup(int daemonize, int argc, char *argv[]){ /* Initialize our global mutex */ pthread_mutex_init(&global_lock, NULL); /* Create the list of context structures and load the * configuration. */ cntlist_create(argc, argv); initialize_chars(); if (daemonize) { /* If daemon mode is requested, and we're not going into setup mode, * become daemon. */ if (cnt_list[0]->daemon && cnt_list[0]->conf.setup_mode == 0) { become_daemon(); motion_log(LOG_INFO, 0, "Motion running as daemon process"); if (cnt_list[0]->conf.low_cpu) { motion_log(LOG_INFO, 0, "Capturing %d frames/s when idle", cnt_list[0]->conf.low_cpu); } } }#ifndef WITHOUT_V4L vid_init();#endif}/** * setup_signals * * Attaches handlers to a number of signals that Motion need to catch. * * Parameters: sigaction structs for signals in general and SIGCHLD. * * Returns: nothing */static void setup_signals(struct sigaction *sig_handler_action, struct sigaction *sigchild_action){#ifdef SA_NOCLDWAIT sigchild_action->sa_flags = SA_NOCLDWAIT;#else sigchild_action->sa_flags = 0;#endif sigchild_action->sa_handler = sigchild_handler; sigemptyset(&sigchild_action->sa_mask);#ifdef SA_RESTART sig_handler_action->sa_flags = SA_RESTART;#else sig_handler_action->sa_flags = 0;#endif sig_handler_action->sa_handler = sig_handler; sigemptyset(&sig_handler_action->sa_mask); /* Enable automatic zombie reaping */ sigaction(SIGCHLD, sigchild_action, NULL); sigaction(SIGPIPE, sigchild_action, NULL); sigaction(SIGALRM, sig_handler_action, NULL); sigaction(SIGHUP, sig_handler_action, NULL); sigaction(SIGINT, sig_handler_action, NULL); sigaction(SIGQUIT, sig_handler_action, NULL); sigaction(SIGTERM, sig_handler_action, NULL); sigaction(SIGUSR1, sig_handler_action, NULL);}/** * main * * Main entry point of Motion. Launches all the motion threads and contains * the logic for starting up, restarting and cleaning up everything. * * Parameters: * * argc - size of argv * argv - command-line options * * Returns: Motion exit status = 0 always */int main (int argc, char **argv){ int i, j; int webcam_port; pthread_attr_t thread_attr; pthread_t thread_id; /* Setup signals and do some initialization. 1 in the call to * 'motion_startup' means that Motion will become a daemon if so has been * requested, and argc and argc are necessary for reading the command * line options. */ struct sigaction sig_handler_action; struct sigaction sigchild_action; setup_signals(&sig_handler_action, &sigchild_action); motion_startup(1, argc, argv);#ifdef HAVE_FFMPEG /* FFMpeg initialization is only performed if FFMpeg support was found * and not disabled during the configure phase. */ ffmpeg_init();#endif /* HAVE_FFMPEG */ /* In setup mode, Motion is very communicative towards the user, which * allows the user to experiment with the config parameters in order to * optimize motion detection and stuff. */ if(cnt_list[0]->conf.setup_mode) motion_log(-1, 0, "Motion running in setup mode."); /* Create and a thread attribute for the threads we spawn later on. * PTHREAD_CREATE_DETACHED means to create threads detached, i.e. * their termination cannot be synchronized through 'pthread_join'. */ pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); /* Create the TLS key for thread number. */ pthread_key_create(&tls_key_threadnr, NULL); do { if (restart) { /* Handle the restart situation. Currently the approach is to * cleanup everything, and then initialize everything again * (including re-reading the config file(s)). */ motion_shutdown(); restart = 0; /* only one reset for now */#ifndef WITHOUT_V4L SLEEP(5,0); // maybe some cameras needs less time#endif motion_startup(0, argc, argv); /* 0 = skip daemon init */ } /* Check the webcam port number for conflicts. * First we check for conflict with the control port. * Second we check for that two threads does not use the same port number * for the webcam. If a duplicate port is found the webcam feature gets disabled (port =0) * for this thread and a warning is written to console and syslog. */ for (i = 1; cnt_list[i]; i++) { /* Get the webcam port for thread 'i', may be 0. */ webcam_port = cnt_list[i]->conf.webcam_port; if (cnt_list[0]->conf.setup_mode) motion_log(LOG_ERR, 0, "Webcam port %d", webcam_port); /* Compare against the control port. */ if (cnt_list[0]->conf.control_port == webcam_port && webcam_port != 0) { cnt_list[i]->conf.webcam_port = 0; motion_log(LOG_ERR, 0, "Webcam port number %d for thread %d conflicts with the control port", webcam_port, i); motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", i); } /* Compare against webcam ports of other threads. */ j = i; while (cnt_list[++j]) { if (cnt_list[j]->conf.webcam_port == webcam_port && webcam_port != 0) { cnt_list[j]->conf.webcam_port = 0; motion_log(LOG_ERR, 0, "Webcam port number %d for thread %d conflicts with thread %d", webcam_port, j, i); motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", j); } } } /* Start the motion threads. First 'cnt_list' item is global if 'thread' * option is used, so start at 1 then and 0 otherwise. */ for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) { /* Assign the thread number for this thread. This is done within a * mutex lock to prevent multiple simultaneous updates to * 'threads_running'. */ pthread_mutex_lock(&global_lock); cnt_list[i]->threadnr = ++threads_running; pthread_mutex_unlock(&global_lock); if ( strcmp(cnt_list[i]->conf_filename,"") ) motion_log(LOG_INFO, 0, "Thread %d is from %s", threads_running, cnt_list[i]->conf_filename ); if (cnt_list[0]->conf.setup_mode) { motion_log(-1, 0, "Thread %d is device: %s input %d", threads_running, cnt_list[i]->conf.netcam_url ? cnt_list[i]->conf.netcam_url : cnt_list[i]->conf.video_device, cnt_list[i]->conf.netcam_url ? -1 : cnt_list[i]->conf.input ); } /* Create the actual thread. Use 'motion_loop' as the thread * function. */ pthread_create(&thread_id, &thread_attr, &motion_loop, cnt_list[i]); } /* Create a thread for the control interface if requested. Create it * detached and with 'motion_web_control' as the thread function. */ if (cnt_list[0]->conf.control_port) pthread_create(&thread_id, &thread_attr, &motion_web_control, cnt_list); if (cnt_list[0]->conf.setup_mode) motion_log(-1, 0,"Waiting for threads to finish, pid: %d", getpid()); /* Crude way of waiting for all threads to finish - check the thread * counter (because we cannot do join on the detached threads). */ while(threads_running > 0) { SLEEP(1,0); } if (cnt_list[0]->conf.setup_mode) motion_log(LOG_DEBUG, 0, "Threads finished"); /* Rest for a while if we're supposed to restart. */ if (restart) SLEEP(2,0); } while (restart); /* loop if we're supposed to restart */ motion_log(LOG_INFO, 0, "Motion terminating"); /* Perform final cleanup. */ pthread_key_delete(tls_key_threadnr); pthread_attr_destroy(&thread_attr); pthread_mutex_destroy(&global_lock); motion_shutdown(); return 0;}/** * mymalloc * * Allocates some memory and checks if that succeeded or not. If it failed, * do some errorlogging and bail out. * * NOTE: Kenneth Lavrsen changed printing of size_t types so instead of using * conversion s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -