// Copyright (c) 2006, Virtual Iron Software, Inc. // All Rights Reserved // Sample program to generate dumps #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct sockaddr SA_t; typedef struct sockaddr_in SIN_t; // Opaque local structure for dumpcore typedef struct dump_args_s { int fd; long total; long last; int linepos; } dump_args_t; static int verbose = 0; /* net_dump - dumpcore callback routine for network connection * * Input: * args dump_args private data pointer * buffer pointer to buffer to be written * length length of buffer * * Output: * none * * Returns: * status */ static int net_dump(void *args, void *buffer, int length) { dump_args_t *da = args; int bytes; int offset; unsigned char *buf = buffer; int max; int linepos; if ( (args == NULL) || (buffer == NULL) || (length < 0) ) return -EINVAL; offset = 0; linepos = 0; while (offset < length) { max = (length-offset > 2048) ? 2048 : length-offset; bytes = write(da->fd, &buf[offset], max); if (bytes < 0) { fprintf(stderr, "? %s: Failed to write buffer, errno %d (%s)\n", __FUNCTION__, errno, strerror(errno)); return -errno; } // Currently, ignore the 0 bytes case of a full buffer. It doesn't // appear to be happening in my testing. If needed, one other // approach might be: if (bytes==0) sleep(1); offset += bytes; da->total += bytes; if ( (da->total - da->last) > (1024*1024)) { if (verbose) { fprintf(stdout, "#"); da->linepos++; if ((da->linepos % 64) == 0) fprintf(stdout, "\n"); fflush(stdout); } da->last = da->total; } } return 0; } /* connect_net_dump - form connection to dump catcher on network * * Input: * host host name in addr:port format * * Output: * none * * Returns: * status */ static int connect_net_dump(char *host) { int cmdSock; SIN_t cmdAddr; int sts; char *portString; int port; char *destString; // Check input if (host == NULL) { fprintf(stderr, "? %s: host name required\n", __FUNCTION__); return -EINVAL; } // Get host and port destString = strdup(host); portString = strchr(destString, ':'); if (portString != NULL) { *portString = '\0'; portString++; port = strtol(portString, NULL, 10); } else port = 778; bzero(&cmdAddr, sizeof(cmdAddr)); cmdAddr.sin_family = AF_INET; cmdAddr.sin_port = htons(port); sts = inet_pton(AF_INET, destString, &cmdAddr.sin_addr.s_addr); if (sts <= 0) { fprintf(stderr, "? %s: inet_pton failed\n", __FUNCTION__); free(destString); return -errno; } if (verbose) fprintf(stdout, "%s: Connecting to %s:%d\n", __FUNCTION__, destString, port); free(destString); // Create socket and connect cmdSock = socket(AF_INET, SOCK_STREAM, 0); if (cmdSock < 0) { fprintf(stderr, "? %s: Unable to create listen socket, errno %d(%s)\n", __FUNCTION__, errno, strerror(errno)); return -errno; } sts = connect(cmdSock, (SA_t *)&cmdAddr, sizeof(cmdAddr)); if (sts == 0) // Return if immediate success return cmdSock; if (errno != EINPROGRESS) { fprintf(stderr, "? %s: Connect failed, errno %d (%s)\n", __FUNCTION__, errno, strerror(errno)); close(cmdSock); return -errno; } return -errno; } /* show_usage - output program usage infomration * * Input: * none * * Output: * none * * Returns: * status 0 for success */ static void show_usage(void) { fprintf(stdout, "Usage: testdump [options]\n"); fprintf(stdout, " -d: dump domain \n"); fprintf(stdout, " -f: dump to with file \n"); fprintf(stdout, " -h: dump to network\n"); fprintf(stdout, " -v be more verbose\n"); return; } int main(int argc, char *argv[]) { int sts; dump_args_t da; int xc_handle; int domid = -1; int fileFlag; int netFlag; char *destName; int ch; destName = strdup(""); while ((ch = getopt(argc, argv, "d:f:h:v")) != -1) { switch(ch) { case 'd': domid = atoi(optarg); break; case 'f': free(destName); destName = strdup(optarg); fileFlag = 1; break; case 'h': free(destName); destName = strdup(optarg); netFlag = 1; break; case 'v': verbose = 1; break; default: fprintf(stderr, "? Unknown argument '%c'\n", ch); show_usage(); return 0; } } argc -= optind; if (argc != 0) { fprintf(stderr, "? Unknown arguments\n"); show_usage(); return 0; } if ( ( (fileFlag == 0) && (netFlag == 0) ) || ( (fileFlag != 0) && (netFlag != 0) ) ) { fprintf(stderr, "? Must specify one dump type of either -f or -h\n"); return EINVAL; } if (domid < 0) { fprintf(stderr, "? Must specify domain id with -d\n"); return EINVAL; } xc_handle = xc_interface_open(); if (netFlag) { da.fd = connect_net_dump(destName); if (da.fd < 0) { return -1; } da.total = 0; da.last = 0; da.linepos = 0; sts = xc_domain_dumpcore2(xc_handle, domid, &da, &net_dump); close(da.fd); } else { sts = xc_domain_dumpcore(xc_handle, domid, destName); } printf("%% %s: xc_dump_domain returned %d\n", __FUNCTION__, sts); return 0; }