#ifndef lint static char sccsid[] = "@(#)sm_proc.c 1.1 88/04/20 4.0NFSSRC Copyr 1988 Sun Micro"; #endif /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ #include #include #include #include #include #include #include #include "sm_statd.h" #include #include #include #include #include #include #define curdir SM_CUR extern int debug; extern int Verbose; int local_state; /* fake local sm state */ int remote_state = 3; /* fake remote sm state for testing */ extern char STATE[], CURRENT[], BACKUP[]; sm_stat_res * sm_stat_1(namep) sm_name *namep; { static sm_stat_res resp; if (debug) printf("sm_stat: mon_name = %s\n", (char *)namep); /* fake answer */ resp.res_stat = stat_fail; resp.state = -1; return(&resp); } sm_stat_res * sm_mon_1(monp) mon *monp; { if (debug) printf("sm_mon: mon_name = %s, id = %d\n", monp->mon_id.mon_name, *((int * )monp->priv)); if (Verbose) { syslog(LOG_INFO, "SM_MON call for %s rejected\n", monp->mon_id.mon_name); } return(NULL); } sm_stat * sm_unmon_1(monidp) mon_id *monidp; { static sm_stat resp; if (debug) printf("sm_unmon: mon_name = %s, [%s, %d, %d, %d]\n", monidp->mon_name, monidp->my_id.my_name, monidp->my_id.my_prog, monidp->my_id.my_vers, monidp->my_id.my_proc); resp.state = local_state; return(&resp); } sm_stat * sm_unmon_all_1(myidp) my_id *myidp; { static sm_stat resp; if (debug) printf("sm_unmon_all: [%s, %d, %d, %d]\n", myidp->my_name, myidp->my_prog, myidp->my_vers, myidp->my_proc); resp.state = local_state; return(&resp); } void sm_simu_crash_1() { if (debug) printf("sm_simu_crash\n"); statd_init(CURRENT, BACKUP, STATE); return; } #include #include struct lockd_args { char la_name[MAXHOSTNAMELEN + 1]; int la_grace; u_int la_lockshares:1; u_int la_setgrace:1; u_int ha_action:2; char ha_dir[MAXPATHLEN + 1]; }; /* * Given a directory, call statd_init() after adding the directory * to the list of HA statmon directories. There are only 2 available * slots for HA statmon directories, one for each node in the cluster. Both * slots are filled only if the local machine is in degraded state. */ sm_stat_res * sm_add_ha_dir_1(sm_name *monp) { static sm_stat_res resp; char *interface, *path_end, *ha_dir, *current, *backup, *state; char string[MAXNAMLEN]; char resolved_path[MAXPATHLEN]; char tmpstring[MAXNAMLEN]; struct lockd_args lockargs; strcpy(string, monp->mon_name); if (debug) printf("sm_add_ha_dir_1: %s\n", string); ha_dir = strrchr(string, ':'); if (ha_dir == NULL) goto fail; *ha_dir = '\0'; ha_dir++; interface = string; if (debug) printf("sm_add_ha_dir_1: (host: %s) (dir: %s)\n", interface, ha_dir); /* * check if the ha_dir string is valid : see if the * path ends in "statmon" * remove the trailing / if there is one */ if (ha_dir[strlen(ha_dir) - 1] == '/') { ha_dir[strlen(ha_dir) - 1] = '\0'; } path_end = strrchr(ha_dir, '/'); if(!path_end) goto fail; path_end++; if (strcmp(path_end, "statmon") != 0) { syslog(LOG_WARNING, "Invalid HA directory %s", ha_dir); goto fail; } if (!realpath(ha_dir, resolved_path)) { if (errno == ENOENT) { path_end--; *path_end = '\0'; if (!realpath(ha_dir, resolved_path)) { *path_end = '/'; syslog(LOG_WARNING, "Invalid realpath for HA directory %s", ha_dir); goto fail; } else if (strcmp(ha_dir, resolved_path) != 0) { *path_end = '/'; syslog(LOG_WARNING, "Invalid realpath for HA directory", ha_dir); goto fail; } *path_end = '/'; } else { syslog(LOG_WARNING, "Invalid HA directory %s", ha_dir); goto fail; } } else if (strcmp(ha_dir, resolved_path) != 0) { syslog(LOG_WARNING, "Invalid HA directory %s", ha_dir); goto fail; } sprintf(tmpstring, "%s/%s", ha_dir, curdir); if (!strcmp(tmpstring, HA_CURRENT) || !strcmp(tmpstring, HA2_CURRENT) ){ syslog(LOG_ERR, "ha_dir %s already added earlier", tmpstring); resp.state = E2BIG; resp.res_stat = stat_fail; return(&resp); } if (HA_CURRENT[0] == '\0') { sprintf(HA_CURRENT, "%s/%s", ha_dir, curdir); sprintf(HA_BACKUP, "%s/%s", ha_dir, backdir); sprintf(HA_STATE, "%s/%s", ha_dir, statefile); current = HA_CURRENT; backup = HA_BACKUP; state = HA_STATE; ha_mode = 1; } else if (HA2_CURRENT[0] == '\0') { sprintf(HA2_CURRENT, "%s/%s", ha_dir, curdir); sprintf(HA2_BACKUP, "%s/%s", ha_dir, backdir); sprintf(HA2_STATE, "%s/%s", ha_dir, statefile); current = HA2_CURRENT; backup = HA2_BACKUP; state = HA2_STATE; ha_mode = 1; } else { syslog(LOG_ERR, "All HA directories already added"); resp.state = E2BIG; resp.res_stat = stat_fail; return(&resp); } if (mkdir(ha_dir, 0755) < 0 && errno != EEXIST) { struct stat hastat; /* if the dir already exists, ignore ENOSPC error */ if(errno == ENOSPC && !stat(ha_dir, &hastat)) syslog(LOG_ERR, "file system almost full"); else { syslog(LOG_ERR, "rpc.statd exiting: can't create %s directory: %m", ha_dir); exit(1); } } /* pass the ha_dir information to the kernel */ lockargs.ha_action = 1; strcpy(lockargs.ha_dir, current); if (syssgi(SGI_LOCKDSYS, &lockargs, sizeof(struct lockd_args))== -1) { syslog(LOG_ERR, "rpc.statd exiting: can't add ha_dir %s to the kernel", current); exit(1); } statd_init(current, backup, state); resp.res_stat = stat_succ; return (&resp); fail: resp.res_stat = stat_fail; return (&resp); } /* sm_add_ha_dir_1 */ /* * Given a directory, delete that directory from one of the two possible * slots. */ sm_stat_res * sm_delete_ha_dir_1(sm_name *monp) { static sm_stat_res resp; char *ha_dir; char ha_current[PATH_MAX]; struct lockd_args lockargs; ha_dir = monp->mon_name; /* * first deal with the "clear ALL" case */ if (!strcmp(ha_dir, "ALL")) { if (debug) printf("Clearing out all ha_dirs\n"); HA_CURRENT[0] = '\0'; HA2_CURRENT[0] = '\0'; ha_mode = 0; lockargs.ha_action = 2; lockargs.ha_dir[0] = '\0'; if (syssgi(SGI_LOCKDSYS, &lockargs, sizeof(struct lockd_args))== -1) { syslog(LOG_ERR,"rpc.statd exiting: can't clear all Ha_dirs from kernel"); exit(1); } resp.res_stat = stat_succ; return (&resp); } if (debug) printf("sm_delete_ha_dir_1: %s\n", ha_dir); sprintf(ha_current, "%s/%s", ha_dir, curdir); if (!strcmp(ha_current, HA_CURRENT)) { HA_CURRENT[0] = '\0'; resp.res_stat = stat_succ; if (HA2_CURRENT[0] == '\0') ha_mode = 0; } else if (!strcmp(ha_current, HA2_CURRENT)) { HA2_CURRENT[0] = '\0'; resp.res_stat = stat_succ; if (HA_CURRENT[0] == '\0') ha_mode = 0; } else { resp.res_stat = stat_fail; syslog(LOG_INFO, "cant delete non-existent ha_dir: %s\n", ha_current); return (&resp); } /* pass the ha_dir information to the kernel */ lockargs.ha_action = 2; strcpy(lockargs.ha_dir, ha_current); if (syssgi(SGI_LOCKDSYS, &lockargs, sizeof(struct lockd_args))== -1) { syslog(LOG_ERR, "can't delete ha_dir %s from kernel", ha_current); resp.res_stat = stat_fail; } return (&resp); } /* sm_delete_ha_dir_1 */ /* * Print out the current HA directories. */ void sm_query_ha_dirs_1(void) { int ha_dirs_printed = 0; struct lockd_args lockargs; if (HA_CURRENT[0] != '\0') { syslog(LOG_ERR, "HA_CURRENT: %s\n", HA_CURRENT); ha_dirs_printed++; } if (HA2_CURRENT[0] != '\0') { syslog(LOG_ERR, "HA2_CURRENT: %s\n", HA2_CURRENT); ha_dirs_printed++; } if (!ha_dirs_printed) syslog(LOG_ERR, "No HA directories added"); /* query the ha_dir information from the kernel */ lockargs.ha_action = 3; if (syssgi(SGI_LOCKDSYS, &lockargs, sizeof(struct lockd_args))== -1) { syslog(LOG_ERR, "rpc.statd exiting: can't query the kernel for HA dirs"); exit(1); } syslog(LOG_INFO, "kern_HA_dir1: %s, kern_HA_dir2 : %s", lockargs.ha_dir, lockargs.la_name); } /* sm_query_ha_dirs_1 */ void sm_notify(stat_chge *ntfp, SVCXPRT *transp) { struct hostent *hp; extern int h_errno; if (debug) printf("sm_notify: %s state =%d\n", ntfp->name, ntfp->state); if (Verbose) { syslog(LOG_INFO, "notification received from %s, state %d", ntfp->name, ntfp->state); } /* * Get the host address and tell the kernel to reclaim any locks it * knows about. */ hp = gethostbyname(ntfp->name); if (!hp) { syslog(LOG_ERR, "sm_notify: unable to get host address for %s: %s\n", ntfp->name, hstrerror(h_errno)); } else if ((syssgi(SGI_NFSNOTIFY, hp->h_addr, hp->h_length) == -1)) { syslog(LOG_ERR, "sm_notify: kernel reclaim for server %s failed: %s\n", ntfp->name, strerror(errno)); } }