📄 halcmd.c
字号:
/** This file, 'halcmd.c', is a HAL component that provides a simple command line interface to the hal. It is a user space component. For detailed instructions, see "man halcmd".*//** Copyright (C) 2003 John Kasunich <jmkasunich AT users DOT sourceforge DOT net> Other contributers: Martin Kuhnle <mkuhnle AT users DOT sourceforge DOT net> Alex Joni <alex_joni AT users DOT sourceforge DOT net> Benn Lipkowitz <fenn AT users DOT sourceforge DOT net> Stephen Wille Padnos <swpadnos AT users DOT sourceforge DOT net> *//** This program is free software; you can redistribute it and/or modify it under the terms of version 2.1 of the GNU General Public License as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of harming persons must have provisions for completely removing power from all motors, etc, before persons enter any danger area. All machinery must be designed to comply with local and national safety codes, and the authors of this software can not, and do not, take any responsibility for such compliance. This code was written as part of the EMC HAL project. For more information, go to www.linuxcnc.org.*/#ifndef ULAPI#error This is a user mode component only!#endif#ifndef EMC2_BIN_DIR#error Need to define EMC2_BIN_DIR so I know where to find emc_module_helper!#endif#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <sys/stat.h>#include <sys/wait.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include "rtapi.h" /* RTAPI realtime OS API */#include "hal.h" /* HAL public API decls */#include "../hal_priv.h" /* private HAL decls *//* non-EMC related uses of halcmd may want to avoid libnml dependency */#ifndef NO_INI#include "inifile.hh" /* iniFind() from libnml */#endif/************************************************************************ LOCAL FUNCTION DECLARATIONS *************************************************************************//* These functions are used internally by this file. The code is at the end of the file. */#define MAX_TOK 20#define MAX_CMD_LEN 1024#define MAX_EXPECTED_SIGS 999static int release_HAL_mutex(void);static int replace_vars(char *source_str, char *dest_str, int max_chars);static int tokenize(char *src, char **tokens);static int parse_cmd(char *tokens[]);static int do_help_cmd(char *command);static int do_lock_cmd(char *command);static int do_unlock_cmd(char *command);static int do_linkpp_cmd(char *first_pin_name, char *second_pin_name);static int do_link_cmd(char *pin, char *sig);static int do_newsig_cmd(char *name, char *type);static int do_setp_cmd(char *name, char *value);static int do_getp_cmd(char *name);static int do_sets_cmd(char *name, char *value);static int do_gets_cmd(char *name);static int do_show_cmd(char *type, char *pattern);static int do_list_cmd(char *type, char *pattern);static int do_status_cmd(char *type);static int do_delsig_cmd(char *mod_name);static int do_loadrt_cmd(char *mod_name, char *args[]);static int do_unloadrt_cmd(char *mod_name);static int do_loadusr_cmd(char *args[]);static int unloadrt_comp(char *mod_name);static void print_comp_info(char *pattern);static void print_pin_info(char *pattern);static void print_sig_info(char *pattern);static void print_script_sig_info(char *pattern);static void print_param_info(char *pattern);static void print_funct_info(char *pattern);static void print_thread_info(char *pattern);static void print_comp_names(char *pattern);static void print_pin_names(char *pattern);static void print_sig_names(char *pattern);static void print_param_names(char *pattern);static void print_funct_names(char *pattern);static void print_thread_names(char *pattern);static void print_lock_status();static int count_list(int list_root);static void print_mem_status();static char *data_type(int type);static char *data_dir(int dir);static char *data_arrow1(int dir);static char *data_arrow2(int dir);static char *data_value(int type, void *valptr);static char *data_value2(int type, void *valptr);static int do_save_cmd(char *type);static void save_comps(void);static void save_signals(void);static void save_links(int arrows);static void save_nets(int arrows);static void save_params(void);static void save_threads(void);static void print_help_general(int showR);static void print_help_commands(void);/************************************************************************ GLOBAL VARIABLES *************************************************************************/int comp_id = -1; /* -1 means hal_init() not called yet */int hal_flag = 0; /* used to indicate that halcmd might have the hal mutex, so the sig handler can't just exit, instead it must set 'done' */int done = 0; /* used to break out of processing loop */int linenumber=0; /* used to print linenumber on errors */int scriptmode = 0; /* used to make output "script friendly" (suppress headers) */int prompt_mode = 0; /* when getting input from stdin, print a prompt */char comp_name[HAL_NAME_LEN]; /* name for this instance of halcmd */#ifndef NO_INI FILE *inifile = NULL;#endif/************************************************************************ MAIN PROGRAM *************************************************************************//* signal handler */static void quit(int sig){ if ( hal_flag ) { /* this process might have the hal mutex, so just set the 'done' flag and return, exit after mutex work finishes */ done = 1; } else { /* don't have to worry about the mutex, but if we just return, we might return into the fgets() and wait all day instead of exiting. So we exit from here. */ if ( comp_id > 0 ) { hal_exit(comp_id); } _exit(1); }}/* tokenize(): this sets an array of pointers to each non-whitespace token in the input line*/static int tokenize(char *cmd_buf, char **tokens){ enum { BETWEEN_TOKENS, IN_TOKEN, SINGLE_QUOTE, DOUBLE_QUOTE, END_OF_LINE } state; char *cp1; int m; /* convert a line of text into individual tokens */ m = 0; cp1 = cmd_buf; state = BETWEEN_TOKENS; while ( m < MAX_TOK ) { switch ( state ) { case BETWEEN_TOKENS: if (( *cp1 == '\n' ) || ( *cp1 == '\0' )) { /* end of the line */ state = END_OF_LINE; } else if ( isspace(*cp1) ) { /* whitespace, skip it */ cp1++; } else { /* first char of a token */ tokens[m] = cp1++; state = IN_TOKEN; } break; case IN_TOKEN: if (( *cp1 == '\n' ) || ( *cp1 == '\0' )) { /* end of the line, terminate current token */ *cp1++ = '\0'; m++; state = END_OF_LINE; } else if ( *cp1 == '\'' ) { /* start of a quoted string */ cp1++; state = SINGLE_QUOTE; } else if ( *cp1 == '\"' ) { /* start of a quoted string */ cp1++; state = DOUBLE_QUOTE; } else if ( isspace(*cp1) ) { /* end of the current token */ *cp1++ = '\0'; m++; state = BETWEEN_TOKENS; } else { /* ordinary character */ cp1++; } break; case SINGLE_QUOTE: if (( *cp1 == '\n' ) || ( *cp1 == '\0' )) { /* end of the line, terminate current token */ *cp1++ = '\0'; m++; state = END_OF_LINE; } else if ( *cp1 == '\'' ) { /* end of quoted string */ cp1++; state = IN_TOKEN; } else { /* ordinary character */ cp1++; } break; case DOUBLE_QUOTE: if (( *cp1 == '\n' ) || ( *cp1 == '\0' )) { /* end of the line, terminate current token */ *cp1++ = '\0'; m++; state = END_OF_LINE; } else if ( *cp1 == '\"' ) { /* end of quoted string */ cp1++; state = IN_TOKEN; } else { /* ordinary character, copy to buffer */ cp1++; } break; case END_OF_LINE: *cp1 = '\0'; tokens[m++] = cp1; break; default: /* should never get here */ return -1; } } return 0;}/* main() is responsible for parsing command line options, and then parsing either a single command from the command line or a series of commands from a file or standard input. It breaks the command[s] into tokens, and passes them to parse_cmd() which does the actual work for each command.*/int main(int argc, char **argv){ int n, fd; int keep_going, retval, errorcount; char *cp1, *filename = NULL; FILE *srcfile = NULL; char raw_buf[MAX_CMD_LEN+1], cmd_buf[2*MAX_CMD_LEN]; char *tokens[MAX_TOK+1]; if (argc < 2) { /* no args specified, print help */ print_help_general(0); exit(0); } /* set default level of output - 'quiet' */ rtapi_set_msg_level(RTAPI_MSG_ERR); /* set default for other options */ keep_going = 0; /* start parsing the command line, options first */ n = 1; while ((n < argc) && (argv[n][0] == '-')) { cp1 = argv[n++]; /* loop to parse grouped options */ while (*(++cp1) != '\0') { switch (*cp1) { case 'R': /* force an unlock of the HAL mutex - to be used after a segfault in a hal program */ if (release_HAL_mutex() != HAL_SUCCESS) { printf("HALCMD: Release Mutex failed!\n"); return 1; } return 0; break; case 'h': /* -h = help */ if (argc > n) { /* there are more arguments, n has been incremented already */ do_help_cmd(argv[n]); } else print_help_general(1); return 0; break; case 'k': /* -k = keep going */ keep_going = 1; break; case 'q': /* -q = quiet (default) */ rtapi_set_msg_level(RTAPI_MSG_ERR); break; case 'Q': /* -Q = very quiet */ rtapi_set_msg_level(RTAPI_MSG_NONE); break; case 's': /* script friendly mode */ scriptmode = 1; break; case 'v': /* -v = verbose */ rtapi_set_msg_level(RTAPI_MSG_INFO); break; case 'V': /* -V = very verbose */ rtapi_set_msg_level(RTAPI_MSG_ALL); break; case 'f': /* -f = read from file (or stdin) */ if (srcfile == NULL) { /* it's the first -f (ignore repeats) */ if ((n < argc) && (argv[n][0] != '-')) { /* there is a following arg, and it's not an option */ filename = argv[n++]; srcfile = fopen(filename, "r"); if (srcfile == NULL) { fprintf(stderr, "Could not open command file '%s'\n", filename); exit(-1); } /* make sure file is closed on exec() */ fd = fileno(srcfile); fcntl(fd, F_SETFD, FD_CLOEXEC); } else { /* no filename followed -f option, use stdin */ srcfile = stdin; prompt_mode = 1; } } break;#ifndef NO_INI case 'i': /* -i = allow reading 'setp' values from an ini file */ if (inifile == NULL) { /* it's the first -i (ignore repeats) */ if ((n < argc) && (argv[n][0] != '-')) { /* there is a following arg, and it's not an option */ filename = argv[n++]; inifile = fopen(filename, "r"); if (inifile == NULL) { fprintf(stderr, "Could not open ini file '%s'\n", filename); exit(-1); } /* make sure file is closed on exec() */ fd = fileno(inifile); fcntl(fd, F_SETFD, FD_CLOEXEC); } else { /* no filename followed -i option, error */ fprintf(stderr, "No missing ini filename for -i option\n"); exit(-1); } } break;#endif /* NO_INI */ default: /* unknown option */ printf("Unknown option '-%c'\n", *cp1); break; } } } /* don't print prompt in script mode (this may change later) */// if (scriptmode != 0) {// prompt_mode = 0;// } /* register signal handlers - if the process is killed we need to call hal_exit() to free the shared memory */ signal(SIGINT, quit); signal(SIGTERM, quit); signal(SIGPIPE, SIG_IGN); /* at this point all options are parsed, connect to HAL */ /* create a unique module name, to allow for multiple halcmd's */ snprintf(comp_name, HAL_NAME_LEN-1, "halcmd%d", getpid()); /* tell the signal handler that we might have the mutex */ hal_flag = 1; /* connect to the HAL */ comp_id = hal_init(comp_name); /* done with mutex */ hal_flag = 0; /* check result */ if (comp_id < 0) { fprintf(stderr, "halcmd: hal_init() failed\n" ); fprintf(stderr, "NOTE: 'rtapi' kernel module must be loaded\n" ); return 1; } retval = 0; errorcount = 0; /* HAL init is OK, let's process the command(s) */ if (srcfile == NULL) { /* the remaining command line args are parts of the command */ /* copy them to a long string for variable replacement */ raw_buf[0] = '\0'; while (n < argc) { strcat(raw_buf, argv[n++]); strcat(raw_buf, " ");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -