📄 rps10.c
字号:
if (gbl_debug) printf ("Calling rps10_hostlist (%s)\n", WTIid); if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "invalid argument to RPS_list_hosts"); return(NULL); } if (!ISCONFIGED(s)) { syslog(LOG_ERR , "unconfigured stonith object in RPS_list_hosts"); return(NULL); } ctx = (struct WTI_RPS10*) s->pinfo; if (ctx->unit_count >= 1) { ret = (char **)MALLOC((ctx->unit_count+1)*sizeof(char*)); if (ret == NULL) { syslog(LOG_ERR, "out of memory"); return NULL; } ret[ctx->unit_count]=NULL; /* null terminate the array */ for (i=0; i<ctx->unit_count; i++) { ret[i] = STRDUP(ctx->controllers[i].node); if (ret[i] == NULL) { for(j=0; j<i; j++) { FREE(ret[j]); } FREE(ret); ret = NULL; break; } } /* end for each possible outlet */ } /* end if any outlets are configured */ return(ret);} /* end si_hostlist() *//* * rps10_free_hostlist - free the result from rps10_hostlist() */static voidrps10_free_hostlist (char ** hlist){ char ** hl = hlist; if (hl == NULL) { return; } while (*hl) { FREE(*hl); *hl = NULL; ++hl; } FREE(hlist);}/* * Parse the given configuration information, and stash * it away... * * The format of <info> for this module is: * <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ... * * e.g. A machine named 'nodea' can kill a machine named 'nodeb' through * a device attached to serial port /dev/ttyS0. * A machine named 'nodeb' can kill machines 'nodea' and 'nodec' * through a device attached to serial port /dev/ttyS1 (outlets 0 * and 1 respectively) * * <assuming this is the heartbeat configuration syntax:> * * stonith nodea rps10 /dev/ttyS0 nodeb 0 * stonith nodeb rps10 /dev/ttyS0 nodea 0 nodec 1 * * Another possible configuration is for 2 stonith devices * accessible through 2 different serial ports on nodeb: * * stonith nodeb rps10 /dev/ttyS0 nodea 0 * stonith nodeb rps10 /dev/ttyS1 nodec 0 *//* * OOPS! * * Most of the large block of comments above is incorrect as far as this * module is concerned. It is somewhat applicable to the heartbeat code, * but not to this Stonith module. * * The format of parameter string for this module is: * <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ... */static intRPS_parse_config_info(struct WTI_RPS10* ctx, const char * info){ char *copy; char *token; char *outlet, *node; if (ctx->config) { /* The module is already configured. */ return(S_OOPS); } /* strtok() is nice to use to parse a string with (other than it isn't threadsafe), but it is destructive, so we're going to alloc our own private little copy for the duration of this function. */ copy = STRDUP(info); if (!copy) { syslog(LOG_ERR, "out of memory"); return S_OOPS; } /* Grab the serial device */ token = strtok (copy, " \t"); if (!token) { syslog(LOG_ERR, "%s: Can't find serial device on config line '%s'", WTIid, info); goto token_error; } ctx->device = STRDUP(token); if (!ctx->device) { syslog(LOG_ERR, "out of memory"); goto token_error; } /* Loop through the rest of the command line which should consist of */ /* <nodename> <outlet> pairs */ while ((node = strtok (NULL, " \t")) && (outlet = strtok (NULL, " \t\n"))) { char outlet_id; /* validate the outlet token */ if ((sscanf (outlet, "%c", &outlet_id) != 1) || !( ((outlet_id >= '0') && (outlet_id <= '9')) || (outlet_id == '*') || (outlet_id == 'A') ) ) { syslog(LOG_ERR , "%s: the outlet_id %s must be between" " 0 and 9 or '*' / 'A'", WTIid, outlet); goto token_error; } if (outlet_id == 'A') { /* Remap 'A' to '*'; in some configurations, * a '*' can't be configured because it breaks * scripts -- lmb */ outlet_id = '*'; } if (ctx->unit_count >= WTI_NUM_CONTROLLERS) { syslog(LOG_ERR, "%s: Tried to configure too many controllers", WTIid); goto token_error; } ctx->controllers[ctx->unit_count].node = STRDUP(node); g_strdown(ctx->controllers[ctx->unit_count].node); ctx->controllers[ctx->unit_count].outlet_id = outlet_id; ctx->unit_count++; } /* free our private copy of the string we've been destructively * parsing with strtok() */ FREE(copy); ctx->config = 1; return ((ctx->unit_count > 0) ? S_OK : S_BADCONFIG);token_error: FREE(copy); return(S_BADCONFIG);}/* * dtrtoggle - toggle DTR on the serial port * * snarfed from minicom, sysdep1.c, a well known POSIX trick. * */static void dtrtoggle(int fd) { struct termios tty, old; int sec = 2; if (gbl_debug) printf ("Calling dtrtoggle (%s)\n", WTIid); tcgetattr(fd, &tty); tcgetattr(fd, &old); cfsetospeed(&tty, B0); cfsetispeed(&tty, B0); tcsetattr(fd, TCSANOW, &tty); if (sec>0) { sleep(sec); tcsetattr(fd, TCSANOW, &old); } if (gbl_debug) printf ("dtrtoggle Complete (%s)\n", WTIid);}/* * RPSConnect - * * Connect to the given WTI_RPS10 device. * Side Effects * DTR on the serial port is toggled * ctx->fd now contains a valid file descriptor to the serial port * ??? LOCK THE SERIAL PORT ??? * * Returns * S_OK on success * S_OOPS on error * S_TIMEOUT if the device did not respond * */static intRPSConnect(struct WTI_RPS10 * ctx){ /* Open the serial port if it isn't already open */ if (ctx->fd < 0) { struct termios tio; ctx->fd = open (ctx->device, O_RDWR); if (ctx->fd <0) { syslog (LOG_ERR, "%s: Can't open %s : %s", WTIid, ctx->device, strerror(errno)); return S_OOPS; } /* set the baudrate to 9600 8 - N - 1 */ memset (&tio, 0, sizeof(tio)); /* ??? ALAN - the -tradtitional flag on gcc causes the CRTSCTS constant to generate a warning, and warnings are treated as errors, so I can't set this flag! - EZA ??? Hmmm. now that I look at the documentation, RTS is just wired high on this device! we don't need it. */ /* tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CRTSCTS ;*/ tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD ; tio.c_lflag = ICANON; if (tcsetattr (ctx->fd, TCSANOW, &tio) < 0) { syslog (LOG_ERR, "%s: Can't set attributes %s : %s", WTIid, ctx->device, strerror(errno)); close (ctx->fd); ctx->fd=-1; return S_OOPS; } /* flush all data to and fro the serial port before we start */ if (tcflush (ctx->fd, TCIOFLUSH) < 0) { syslog (LOG_ERR, "%s: Can't flush %s : %s", WTIid, ctx->device, strerror(errno)); close (ctx->fd); ctx->fd=-1; return S_OOPS; } } /* Toggle DTR - this 'resets' the controller serial port interface In minicom, try CTRL-A H to hangup and you can see this behavior. */ dtrtoggle(ctx->fd); /* Wait for the switch to respond with "RPS-10 Ready". Emperically, this usually takes 5-10 seconds... ... If this fails, this may be a hint that you got a broken serial cable, which doesn't connect hardware flow control. */ if (gbl_debug) printf ("Waiting for READY\n"); EXPECT(WTItokReady, 12); if (gbl_debug) printf ("Got READY\n"); EXPECT(WTItokCRNL, 2); if (gbl_debug) printf ("Got NL\n"); return(S_OK);}static intRPSDisconnect(struct WTI_RPS10 * ctx){ if (ctx->fd >= 0) { /* Flush the serial port, we don't care what happens to the characters and failing to do this can cause close to hang. */ tcflush(ctx->fd, TCIOFLUSH); close (ctx->fd); } ctx->fd = -1; return S_OK;} /* * RPSNametoOutlet - Map a hostname to an outlet on this stonith device. * * Returns: * 0-9, * on success ( the outlet id on the RPS10 ) * -1 on failure (host not found in the config file) * */static signed charRPSNametoOutlet ( struct WTI_RPS10 * ctx, const char * host ){ int i=0; char *shost; if ( (shost = STRDUP(host)) == NULL) { syslog(LOG_ERR, "strdup failed in RPSNametoOutlet"); return -1; } g_strdown(shost); /* scan the controllers[] array to see if this host is there */ for (i=0;i<ctx->unit_count;i++) { /* return the outlet id */ if ( ctx->controllers[i].node && !strcmp(host, ctx->controllers[i].node)) { /* found it! */ break; } } free(shost); if (i == ctx->unit_count) { return -1; } else { return ctx->controllers[i].outlet_id; }}/* * rps10_reset - API call to Reset (reboot) the given host on * this Stonith device. This involves toggling the power off * and then on again, OR just calling the builtin reset command * on the stonith device. */static intrps10_reset_req(Stonith * s, int request, const char * host){ int rc = S_OK; int lorc = S_OK; signed char outlet_id = -1; struct WTI_RPS10* ctx; if (gbl_debug) printf ("Calling rps10_reset (%s)\n", WTIid); if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "invalid argument to RPS_reset_host"); return(S_OOPS); } if (!ISCONFIGED(s)) { syslog(LOG_ERR , "unconfigured stonith object in RPS_reset_host"); return(S_OOPS); } ctx = (struct WTI_RPS10*) s->pinfo; if ((rc = RPSConnect(ctx)) != S_OK) { return(rc); } outlet_id = RPSNametoOutlet(ctx, host); if (outlet_id < 0) { syslog(LOG_WARNING, _("%s %s " "doesn't control host [%s]."), ctx->idinfo, ctx->unitid, host); RPSDisconnect(ctx); return(S_BADHOST); } switch(request) {#if defined(ST_POWERON) case ST_POWERON: rc = RPSOn(ctx, outlet_id, host); break;#endif#if defined(ST_POWEROFF) case ST_POWEROFF: rc = RPSOff(ctx, outlet_id, host); break;#endif case ST_GENERIC_RESET: rc = RPSReset(ctx, outlet_id, host); break; default: rc = S_INVAL; break; } lorc = RPSDisconnect(ctx); return(rc != S_OK ? rc : lorc);}/* * Parse the information in the given configuration file, * and stash it away... */static intrps10_set_config_file(Stonith* s, const char * configname){ FILE * cfgfile; char RPSid[256]; struct WTI_RPS10* ctx; if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "invalid argument to RPS_set_configfile"); return(S_OOPS); } ctx = (struct WTI_RPS10*) s->pinfo; if ((cfgfile = fopen(configname, "r")) == NULL) { syslog(LOG_ERR, _("Cannot open %s"), configname); return(S_BADCONFIG); } while (fgets(RPSid, sizeof(RPSid), cfgfile) != NULL){ switch (RPSid[0]){ case '\0': case '\n': case '\r': case '#': continue; } /* We can really only handle one line. Wimpy. */ return RPS_parse_config_info(ctx, RPSid); } return(S_BADCONFIG);}/* * rps10_set_config_info - API entry point to process one line of config info * for this particular device. * * Parse the config information in the given string, and stash it away... * */static intrps10_set_config_info(Stonith* s, const char * info){ struct WTI_RPS10* ctx; if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "RPS_provide_config_info: invalid argument"); return(S_OOPS); } ctx = (struct WTI_RPS10 *)s->pinfo; return(RPS_parse_config_info(ctx, info));}/* * rps10_getinfo - API entry point to retrieve something from the handle */static const char *rps10_getinfo(Stonith * s, int reqtype){ struct WTI_RPS10* ctx; const char * ret; if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "RPS_idinfo: invalid argument"); return NULL; } /* * We look in the ST_TEXTDOMAIN catalog for our messages */ ctx = (struct WTI_RPS10 *)s->pinfo; switch (reqtype) { case ST_DEVICEID: ret = ctx->idinfo; break; case ST_CONF_INFO_SYNTAX: ret = _("<serial_device> <node> <outlet> " "[ <node> <outlet> [...] ]\n" "All tokens are white-space delimited.\n"); break; case ST_CONF_FILE_SYNTAX: ret = _("<serial_device> <node> <outlet> " "[ <node> <outlet> [...] ]\n" "All tokens are white-space delimited.\n" "Blank lines and lines beginning with # are ignored"); break; case ST_DEVICEDESCR: ret = _("Western Telematic Inc. (WTI) " "Remote Power Switch - RPS-10M.\n"); break; case ST_DEVICEURL: ret = "http://www.wti.com/"; break; default: ret = NULL; break; } return ret;}/* * rps10_destroy - API entry point to destroy a WTI_RPS10 Stonith object. */static voidrps10_destroy(Stonith *s){ struct WTI_RPS10* ctx; if (!ISWTIRPS10(s)) { syslog(LOG_ERR, "wti_rps10_del: invalid argument"); return; } ctx = (struct WTI_RPS10 *)s->pinfo; ctx->WTIid = NOTwtiid; /* close the fd if open and set ctx->fd to invalid */ RPSDisconnect(ctx); if (ctx->device != NULL) { FREE(ctx->device); ctx->device = NULL; } if (ctx->idinfo != NULL) { FREE(ctx->idinfo); ctx->idinfo = NULL; } if (ctx->unitid != NULL) { FREE(ctx->unitid); ctx->unitid = NULL; }}/* * rps10_new - API entry point called to create a new WTI_RPS10 Stonith device * object. */static void *rps10_new(void){ struct WTI_RPS10* ctx = MALLOCT(struct WTI_RPS10); if (ctx == NULL) { syslog(LOG_ERR, "out of memory"); return(NULL); } memset(ctx, 0, sizeof(*ctx)); ctx->WTIid = WTIid; ctx->fd = -1; ctx->config = 0; ctx->unit_count = 0; ctx->device = NULL; ctx->idinfo = NULL; ctx->unitid = NULL; REPLSTR(ctx->idinfo, DEVICE); REPLSTR(ctx->unitid, "unknown"); return((void *)ctx);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -