/* Mark5Com * I connect to socket m5drive (cf., /etc/services) * on the Mark5A machine specified in my calling sequence. * The program Mark5A must be running on that machine, else this * connection fails. Then I send a Mark5A command (cf., Mark5A.c) * through the socket to program Mark5A, and return the response. * Note that this version is intended to compile on HP-UX. * Revised: 2002 August 27, JAB */ #include "Mark5Com.h" static struct Machn machn[MAXDISCS]; /* Up to MAXDISCS Mark-5 machines */ char * Mark5Com (char * machine, char * inLine) { static int first = TRUE; /* First time here? */ int indx; /* Index into machn[] for this machine */ int i, len; /* Scratch */ struct servent * set; /* From getservbyname() */ struct sockaddr_in socaddin; /* For connect() info */ struct hostent * hostinfo; /* From gethostbyname() */ unsigned char * uc; /* To debug print IP address */ /* ** Initialize ** */ if (first) { /* First time here? */ for (i = 0; i < MAXDISCS; i++) { /* Yes. Each possible Mark-5 machine */ machn[i].name[0] = '\0'; /* Null machine name */ machn[i].sock = -1; /* No socket */ machn[i].fsock = NULL; /* No stream */ machn[i].outLine[0] = '\0'; /* No answer yet */ } /* End of for i each machine */ first = FALSE; /* Never again */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: machine %s, inLine %s", me, machine, inLine); /* ** Check for certain errors ** */ if (strlen(machine) < 3 || strlen(inLine) < 4) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 machine %s and/or inLine %s illegal \n", me, machine, inLine); return(NULL); /* Error */ } /* ** Find index to this machine, if any ** */ indx = -1; /* Initialize to not found */ for (i = 0; i < MAXDISCS; i++) /* Each possible Mark-5 machine */ if (strcmp(machine, machn[i].name) == 0) { /* This one? */ indx = i; /* Yes */ break; /* Found */ } /* (Else indx stays -1) */ /* ** The command "exit" is a special case: Close socket ** */ if (strncasecmp(inLine, "exit", 4) == 0) { /* Exit? */ if (indx >= 0) { /* Yes. OK indx? */ (void) close(machn[indx].sock); /* Yes */ machn[indx].name[0] = '\0'; /* This entry is no longer in use */ } return("OK \n"); /* Exit special case */ } /* ** Check for certain other errors ** */ if ((len = strlen(inLine)) < 5) { /* Command or query OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 Illegal command or query: %s \n", inLine, me); return(NULL); /* Error */ } /* Else len is used later */ /* ** Open a socket to this machine if need be ** */ if (indx < 0) { /* New socket needed? */ /* Yes. First find an empty entry in the machn[] database */ for (i = 0; i < MAXDISCS; i++) /* Each possible Mark-5 machine */ if (machn[i].name[0] == '\0') { /* Null machine name? */ indx = i; /* Yes, use this one */ break; /* Found */ } if (indx < 0) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 machn[] database is full \n", me); return(NULL); /* Error */ } (void) strncpy(machn[indx].name, machine, 64); /* Save machine name */ /* * Create a socket * */ if ((machn[indx].sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 socket() returned %d ", me, machn[indx].sock); perror("error"); machn[indx].name[0] = '\0'; /* No socket, no name */ return(NULL); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s Mark5Com() DEBUG: sock is %d \n", me, machn[indx].sock); socaddin.sin_family = PF_INET; /* To agree with socket() */ /* * Get service number for socket m5drive * */ if ((set = getservbyname("m5drive", "tcp")) == NULL) { /* Errors? */ (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 m5drive tcp " /* Yes */ "not found in /etc/services \n", me); (void) close(machn[indx].sock); machn[indx].name[0] = '\0'; /* No name */ return(NULL); /* Error */ } socaddin.sin_port = set->s_port; /* Port m5drive's number */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s Mark5Com() DEBUG: m5drive port is %d \n", me, ntohs(socaddin.sin_port)); /* * Find an IP address of the machine to connect to * */ if ((hostinfo = gethostbyname(machn[indx].name)) == NULL) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 gethostbyname() on %s returned NULL ", me, machn[indx].name); herror("error"); /* Error */ switch (h_errno) { /* Which error? */ case HOST_NOT_FOUND : (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 " "Host %s not found \n", me, machn[indx].name); break; case TRY_AGAIN : (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 No response, try again later \n", me); break; case NO_RECOVERY : (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 Unknown error, not recoverable \n", me); break; case NO_ADDRESS : /* = NO_DATA */ (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 No Internet address available \n", me); break; } /* End of switch */ (void) close(machn[indx].sock); machn[indx].name[0] = '\0'; return(NULL); /* Error */ } /* End of if hostinfo NULL */ if (hostinfo->h_addr_list[0] == NULL) { /* First IP address OK? */ (void) fprintf(stderr, "%s Mark5Com() ERROR: \007 gethostbyname() " "on %s returned NULL IP address \n", me, machn[indx].name); (void) close(machn[indx].sock); machn[indx].name[0] = '\0'; return(NULL); /* Error */ } if (msglev < 1) { /* Debuggery? */ uc = (unsigned char *) hostinfo->h_addr_list[0]; /* Yes */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: IP address of %s is [", me, machn[indx].name); for (i = 0; i < hostinfo->h_length; i++) { if (i > 0) (void) printf("."); (void) printf("%u", uc[i]); } (void) printf("] \n"); } socaddin.sin_addr.s_addr = *((unsigned long *) hostinfo->h_addr_list[0]); /* Use first address */ /* * Connect this socket to Mark5A on machine * */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, "%s Mark5Com() DEBUG: Trying to connect() \n", me); if (connect(machn[indx].sock, (const struct sockaddr *) &socaddin, sizeof(struct sockaddr_in)) < 0) { /* Connect OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 Connect() returned ", me); perror("error"); (void) close(machn[indx].sock); machn[indx].name[0] = '\0'; return(NULL); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: Got a connect() on sock %d \n", me, machn[indx].sock); /* * Open socket also to read as a stream * */ if ((machn[indx].fsock = fdopen(machn[indx].sock, "r")) == NULL) { (void) fprintf(stderr, /* Not OK */ "%s Mark5Com() ERROR: \007 fdopen() on sock %d returned ", me, machn[indx].sock); perror("error"); (void) close(machn[indx].sock); machn[indx].name[0] = '\0'; return(NULL); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: Socket %d open also as a stream \n", me, machn[indx].sock); } /* End of if indx, open a socket to this machine */ /* Here indx specifies a socket open to machine and open also as a stream */ /* ** Send the command or query ** */ if (send(machn[indx].sock, inLine, len, 0) < len) { /* Send to socket, OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 send() on socket returned ", me); perror("error"); (void) close(machn[indx].sock); /* Error */ machn[indx].name[0] = '\0'; return(NULL); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: Sent inLine to socket %d \n", me, machn[indx].sock); /* ** Read reply (from stream) ** */ if (fgets(machn[indx].outLine, sizeof(machn[indx].outLine), machn[indx].fsock) == NULL) { /* OK? */ (void) fprintf(stderr, /* Nope */ "%s Mark5Com() ERROR: \007 fgets() on socket %d returned ", me, machn[indx].sock); perror("error"); (void) close(machn[indx].sock); /* Error */ machn[indx].name[0] = '\0'; return(NULL); /* Error */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Mark5Com() DEBUG: outLine %s", me, machn[indx].outLine); /* ** Return reply ** */ return(machn[indx].outLine); } /* End of Mark5Com() */ int Error5Com(char * astring) { /* Error5Com() accepts a string returned by Parse5A() (perhaps * through Mark5Com()), parses and returns the error number, which * is the first argument or second token and is 0 for no error. * Or return negative for certain parsing failures. */ static char * sepr = " =:;\t\n\r"; /* Token separators */ char acopy[1024]; /* Copy of astring */ char * ptr; /* First make a copy of astring to trash */ (void) strncpy(acopy, astring, sizeof(acopy)); if (strtok(acopy, sepr) == NULL || (ptr = strtok(NULL, sepr)) == NULL) { /* First two tokens, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s Error5Com() WARNING: Can't parse astring %s \n", me, astring); return(-1); /* Error */ } return(atoi(ptr)); /* Second token is error code */ } /* End of Error5Com() */ int TOT5Com(char * astring, double * ptot, long long * pbyte) { /* TOT5Com() accepts a string returned by Parse5A() after a * "data_check?" query (perhaps through Mark5Com()), finds and * parses the fourth token, data time, converts it to systics, * and returns the resulting TOT in *ptot, parses the fifth * token, converts it to a long long, and returns it it *pbyte. * TOT5Com returns 0 on success or negative on error. */ static char * sepr = " =:;\t\n\r"; /* Token separators */ char acopy[1024]; /* Copy of astring */ char * ptr; int yy, dd, hh, mm, k; double ss; (void) strncpy(acopy, astring, sizeof(acopy)); /* Copy of astring to trash */ /* Parse over to date and time */ if (strtok(acopy, sepr) == NULL || /* ("!data_check?") */ strtok(NULL, sepr) == NULL || /* (error number) */ strtok(NULL, sepr) == NULL || /* (data format) */ strtok(NULL, sepr) == NULL || /* (track mode) */ (ptr = strtok(NULL, sepr)) == NULL) { /* (data time) */ /* First four tokens, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s TOT5Com() WARNING: Can't parse to date/time in astring %s \n", me, astring); return(-1); /* Error */ } /* Now parse date and time */ k = sscanf(ptr, "%dy%dd%dh%dm%lfs", &yy, &dd, &hh, &mm, &ss); /* Check for errors */ if (k != 5 || dd < 0 || dd > 366 || hh < 0 || hh > 24 || mm < 0 || mm > 60 || ss < 0.0 || ss > 60.0) { /* OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s TOT5Com() WARNING: Can't parse date/time in astring %s \n", me, astring); return(-2); /* Error */ } *ptot = ((((dd - 1) * 24.0 + hh) * 60.0 + mm) * 60.0 + ss) * 32.0e6; /* Date to TOT */ if ((ptr = strtok(NULL, sepr)) == NULL) { /* (bytes) */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s TOT5Com() WARNING: Can't parse bytes in astring %s \n", me, astring); return(-3); /* Error */ } (void) sscanf(ptr, "%lld", pbyte); /* Get bytes */ /* (Apparently HP-UX has no atoll()) */ return(0); /* Normal end */ } /* End of TOT5Com() */ int DiskInfo(char * machine, struct discinfo * dnfo) { /* This function accepts a machine name and fills in as much as * possible of the discinfo structures by calling Mark5Com(). * dnfo[] should be an array of MAXDISCS structures (cf., lvex.h). * Return number of disks found or negative on error. * Struct discinfo is in ivex.h */ static char * sepr = " =:;\t\n\r"; /* Token separators */ char * ans; /* Return from Parse5A() */ char acopy[1024]; /* Copy of return from Parse5A() through Mark5Com() */ char * ptr; /* Scratch */ int i; /* ** First get disk serial numbers ** */ ans = Mark5Com(machine, "disc_serial? ;\n"); (void) strncpy(acopy, ans, sizeof(acopy)); /* Copy to trash */ if (strtok(acopy, sepr) == NULL || /* ("!disc_serial?") */ strtok(NULL, sepr) == NULL || /* (error number) */ (ptr = strtok(NULL, sepr)) == NULL) { /* (first serial number) */ /* First three tokens, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Can't parse astring %s \n", me, ans); return(-1); /* Error */ } (void) strncpy(dnfo[0].disc_serial_num, ptr, MAX_NAMESIZE); /* First */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() DEBUG: First serial %s \n", me, dnfo[0].disc_serial_num); for (i = 1; i < MAXDISCS; i++) { /* Up to 15 more disks */ if ((ptr = strtok(NULL, sepr)) == NULL) /* OK? */ break; /* Nope, no more disks, out of for i */ /* Else OK, got this disk */ (void) strncpy(dnfo[i].disc_serial_num, ptr, MAX_NAMESIZE); } if (msglev < 1) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Got just %d disk(s) \n", me, i); /* ** Next disk model names ** */ ans = Mark5Com(machine, "disc_model? ;\n"); (void) strncpy(acopy, ans, sizeof(acopy)); /* Copy to trash */ if (strtok(acopy, sepr) == NULL || /* ("!disc_model?") */ strtok(NULL, sepr) == NULL || /* (error number) */ (ptr = strtok(NULL, sepr)) == NULL) { /* (first model name) */ /* First three tokens, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Can't parse astring %s \n", me, ans); return(-1); /* Error */ } (void) strncpy(dnfo[0].disc_model_num, ptr, MAX_NAMESIZE); /* First disk */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() DEBUG: First model %s \n", me, dnfo[0].disc_model_num); for (i = 1; i < MAXDISCS; i++) { /* Up to 15 more disks */ if ((ptr = strtok(NULL, sepr)) == NULL) /* OK? */ break; /* Nope, no more disks, out of for i */ /* Else OK, got this disk */ (void) strncpy(dnfo[i].disc_model_num, ptr, MAX_NAMESIZE); } if (msglev < 1) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Got just %d disk(s) \n", me, i); /* ** Last disk sizes ** */ ans = Mark5Com(machine, "disc_size? ;\n"); (void) strncpy(acopy, ans, sizeof(acopy)); /* Copy to trash */ if (strtok(acopy, sepr) == NULL || /* ("!disc_size?") */ strtok(NULL, sepr) == NULL || /* (error number) */ (ptr = strtok(NULL, sepr)) == NULL) { /* (first size) */ /* First three tokens, OK? */ if (msglev < 2) /* Nope. Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Can't parse astring %s \n", me, ans); return(-1); /* Error */ } dnfo[0].disc_size = atof(ptr) / 1.0e9; /* First disk size to Gbytes */ /* (Note truncate rather than round) */ if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() DEBUG: First model %s \n", me, dnfo[0].disc_model_num); for (i = 1; i < MAXDISCS; i++) { /* Up to 15 more disks */ if ((ptr = strtok(NULL, sepr)) == NULL) /* OK? */ break; /* Nope, no more disks, out of for i */ /* Else OK, got this disk */ dnfo[i].disc_size = atof(ptr) / 1.0e9; /* Disk size to Gbytes */ } if (msglev < 1) /* Debuggery? */ (void) fprintf(stderr, /* Yes */ "%s DiskInfo() WARNING: Got just %d disk(s) \n", me, i); return(i); } /* End of DiskInfo() */