size_t printXMLStatInfo(FILE *out, int indent, const char* tag, const char* id, const StatInfo* info, int includeData, int useCDATA) { char *real = NULL; /* sanity check */ if (info->source == IS_INVALID) { return 0; } /* start main tag */ fprintf(out, "%*s<%s error=\"%d\"", indent, "", tag, info->error); if (id != NULL) { fprintf(out, " id=\"%s\"", id); } if (info->lfn != NULL) { fprintf(out, " lfn=\"%s\"", info->lfn); } fprintf(out, ">\n"); /* NEW: ignore "file not found" error for "kickstart" */ if (id != NULL && info->error == 2 && strcmp(id, "kickstart") == 0) { fprintf(out, "%*s<!-- ignore above error -->\n", indent+2, ""); } /* either a <name> or <descriptor> sub element */ switch (info->source) { case IS_TEMP: /* preparation for <temporary> element */ /* late update for temp files */ errno = 0; if (fstat(info->file.descriptor, (struct stat*) &info->info) != -1 && (((StatInfo*) info)->error = errno) == 0) { /* obtain header of file */ int fd = dup(info->file.descriptor); if (fd != -1) { if (lseek(fd, 0, SEEK_SET) != -1) { read(fd, (char*) info->client.header, sizeof(info->client.header)); } close(fd); } } fprintf(out, "%*s<temporary name=\"%s\" descriptor=\"%d\"/>\n", indent+2, "", info->file.name, info->file.descriptor); break; case IS_FIFO: /* <fifo> element */ fprintf(out, "%*s<fifo name=\"%s\" descriptor=\"%d\" count=\"%zu\" rsize=\"%zu\" wsize=\"%zu\"/>\n", indent+2, "", info->file.name, info->file.descriptor, info->client.fifo.count, info->client.fifo.rsize, info->client.fifo.wsize); break; case IS_FILE: /* <file> element */ real = realpath(info->file.name, NULL); fprintf(out, "%*s<file name=\"%s\"", indent+2, "", real ? real : info->file.name); if (real) { free((void*) real); } if (info->error == 0 && S_ISREG(info->info.st_mode) && info->info.st_size > 0) { /* optional hex information */ size_t i, end = sizeof(info->client.header); if (info->info.st_size < end) end = info->info.st_size; fprintf(out, ">"); for (i=0; i<end; ++i) { fprintf(out, "%02X", info->client.header[i]); } fprintf(out, "</file>\n"); } else { fprintf(out, "/>\n"); } break; case IS_HANDLE: /* <descriptor> element */ fprintf(out, "%*s<descriptor number=\"%u\"/>\n", indent+2, "", info->file.descriptor); break; default: /* this must not happen! */ fprintf(out, "%*s<!-- ERROR: No valid file info available -->\n", indent+2, ""); break; } if (info->error == 0 && info->source != IS_INVALID) { /* <stat> subrecord */ char my[32]; struct passwd* user = getpwuid(info->info.st_uid); struct group* group = getgrgid(info->info.st_gid); fprintf(out, "%*s<statinfo mode=\"0%o\"", indent+2, "", info->info.st_mode); /* Grmblftz, are we in 32bit, 64bit LFS on 32bit, or 64bit on 64 */ sizer(my, sizeof(my), sizeof(info->info.st_size), &info->info.st_size); fprintf(out, " size=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_ino), &info->info.st_ino); fprintf(out, " inode=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_nlink), &info->info.st_nlink); fprintf(out, " nlink=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_blksize), &info->info.st_blksize); fprintf(out, " blksize=\"%s\"", my); /* st_blocks is new in iv-1.8 */ sizer(my, sizeof(my), sizeof(info->info.st_blocks), &info->info.st_blocks); fprintf(out, " blocks=\"%s\"", my); fprintf(out, " mtime=\"%s\"", fmtisodate(info->info.st_mtime, -1)); fprintf(out, " atime=\"%s\"", fmtisodate(info->info.st_atime, -1)); fprintf(out, " ctime=\"%s\"", fmtisodate(info->info.st_ctime, -1)); fprintf(out, " uid=\"%d\"", info->info.st_uid); if (user) { fprintf(out, " user=\"%s\"", user->pw_name); } fprintf(out, " gid=\"%d\"", info->info.st_gid); if (group) { fprintf(out, " group=\"%s\"", group->gr_name); } fprintf(out, "/>\n"); } /* data section from stdout and stderr of application */ if (includeData && info->source == IS_TEMP && info->error == 0 && info->info.st_size && data_section_size > 0) { size_t dsize = data_section_size; size_t fsize = info->info.st_size; fprintf(out, "%*s<data%s", indent+2, "", (fsize > dsize ? " truncated=\"true\"" : "")); if (fsize > 0) { char buf [BUFSIZ]; int fd = dup(info->file.descriptor); fprintf(out, ">"); if (fd != -1) { if (useCDATA) { fprintf(out, "<![CDATA["); } /* Get the last dsize bytes of the file */ size_t offset = 0; if (fsize > dsize) { offset = fsize - dsize; } if (lseek(fd, offset, SEEK_SET) != -1) { ssize_t total = 0; while (total < dsize) { ssize_t rsize = read(fd, buf, BUFSIZ); if (rsize == 0) { break; } else if (rsize < 0) { printerr("ERROR reading %s: %s", info->file.name, strerror(errno)); break; } if (useCDATA) { fwrite(buf, rsize, 1, out); } else { xmlquote(out, buf, rsize); } total += rsize; } } close(fd); if (useCDATA) { fprintf(out, "]]>"); } } fprintf(out, "</data>\n"); } else { fprintf(out, "/>\n"); } } fprintf(out, "%*s</%s>\n", indent, "", tag); return 0; }
int printXMLJobInfo(FILE *out, int indent, const char* tag, const JobInfo* job) /* purpose: format the job information into the given stream as XML. * paramtr: out (IO): the stream * indent (IN): indentation level * tag (IN): name to use for element tags. * job (IN): job info to print. * returns: number of characters put into buffer (buffer length) */ { int status; /* $#@! broken Debian headers */ /* sanity check */ if (!job->isValid) return 0; /* start tag with indentation */ fprintf(out, "%*s<%s start=\"%s\"", indent, "", tag, fmtisodate(isLocal, isExtended, job->start.tv_sec, job->start.tv_usec)); fprintf(out, " duration=\"%.3f\"", doubletime(job->finish) - doubletime(job->start)); /* optional attribute: application process id */ if (job->child != 0) fprintf(out, " pid=\"%d\"", job->child); /* finalize open tag of element */ fprintf(out, ">\n"); /* <usage> */ printXMLUseInfo(out, indent+2, "usage", &job->use); /* <status>: open tag */ fprintf(out, "%*s<status raw=\"%d\">", indent+2, "", job->status); /* <status>: cases of completion */ status = (int) job->status; /* $#@! broken Debian headers */ if (job->status < 0) { /* <failure> */ fprintf(out, "<failure error=\"%d\">%s%s</failure>", job->saverr, job->prefix && job->prefix[0] ? job->prefix : "", strerror(job->saverr)); } else if (WIFEXITED(status)) { fprintf(out, "<regular exitcode=\"%d\"/>", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { /* result = 128 + WTERMSIG(status); */ fprintf(out, "<signalled signal=\"%u\"", WTERMSIG(status)); #ifdef WCOREDUMP fprintf(out, " corefile=\"%s\"", WCOREDUMP(status) ? "true" : "false"); #endif fprintf(out, ">%s</signalled>", #if defined(CYGWINNT50) || defined(CYGWINNT51) "unknown" #else sys_siglist[WTERMSIG(status)] #endif ); } else if (WIFSTOPPED(status)) { fprintf(out, "<suspended signal=\"%u\">%s</suspended>", WSTOPSIG(status), #if defined(CYGWINNT50) || defined(CYGWINNT51) "unknown" #else sys_siglist[WSTOPSIG(status)] #endif ); } /* FIXME: else? */ fprintf(out, "</status>\n"); /* <executable> */ printXMLStatInfo(out, indent+2, "statcall", NULL, &job->executable); #ifdef WITH_NEW_ARGS /* alternative 1: new-style <argument-vector> */ fprintf(out, "%*s<argument-vector", indent+2, ""); if (job->argc == 1) { /* empty element */ fprintf(out, "/>\n"); } else { /* content are the CLI args */ int i; fprintf(out, ">\n"); for (i=1; i<job->argc; ++i) { fprintf(out, "%*s<arg nr=\"%d\">", indent+4, "", i); xmlquote(out, job->argv[i], strlen(job->argv[i])); fprintf(out, "</arg>\n"); } /* end tag */ fprintf(out, "%*s</argument-vector>\n", indent+2, ""); } #else /* alternative 2: old-stlye <arguments> */ fprintf(out, "%*s<arguments", indent+2, ""); if (job->argc == 1) { /* empty element */ fprintf(out, "/>\n"); } else { /* content are the CLI args */ int i = 1; fprintf(out, ">"); while (i < job->argc) { xmlquote(out, job->argv[i], strlen(job->argv[i])); if (++i < job->argc) fprintf(out, " "); } /* end tag */ fprintf(out, "</arguments>\n"); } #endif /* WITH_NEW_ARGS */ /* <proc>s */ printXMLProcInfo(out, indent+2, job->children); /* finalize close tag of outmost element */ fprintf(out, "%*s</%s>\n", indent, "", tag); return 0; }
size_t printXMLStatInfo(FILE *out, int indent, const char* tag, const char* id, const StatInfo* info) /* purpose: XML format a stat info record into a given stream * paramtr: out (IO): the stream * tag (IN): name of element to generate * id (IN): id attribute, use NULL to not generate * info (IN): stat info to print. * returns: number of characters put into buffer (buffer length) */ { char* real = NULL; /* sanity check */ if (info->source == IS_INVALID) return 0; /* start main tag */ fprintf(out, "%*s<%s error=\"%d\"", indent, "", tag, info->error); if (id != NULL) fprintf(out, " id=\"%s\"", id); if (info->lfn != NULL) fprintf(out, " lfn=\"%s\"", info->lfn); fprintf(out, ">\n"); /* NEW: ignore "file not found" error for "gridstart" */ if (id != NULL && info->error == 2 && strcmp(id, "gridstart") == 0) fprintf(out, "%*s<!-- ignore above error -->\n", indent+2, ""); /* either a <name> or <descriptor> sub element */ switch (info->source) { case IS_TEMP: /* preparation for <temporary> element */ /* late update for temp files */ errno = 0; if (fstat(info->file.descriptor, (struct stat*) &info->info) != -1 && (((StatInfo*) info)->error = errno) == 0) { /* obtain header of file */ #if 0 /* implementation alternative 1: use a new filetable kernel structure */ int fd = open(info->file.name, O_RDONLY); if (fd != -1) { read(fd, (char*) info->client.header, sizeof(info->client.header)); close(fd); } #else /* implementation alternative 2: share the kernel filetable structure */ int fd = dup(info->file.descriptor); if (fd != -1) { if (lseek(fd, 0, SEEK_SET) != -1) read(fd, (char*) info->client.header, sizeof(info->client.header)); close(fd); } #endif } fprintf(out, "%*s<temporary name=\"%s\" descriptor=\"%d\"/>\n", indent+2, "", info->file.name, info->file.descriptor); break; case IS_FIFO: /* <fifo> element */ fprintf(out, "%*s<fifo name=\"%s\" descriptor=\"%d\" count=\"%zu\" rsize=\"%zu\" wsize=\"%zu\"/>\n", indent+2, "", info->file.name, info->file.descriptor, info->client.fifo.count, info->client.fifo.rsize, info->client.fifo.wsize); break; case IS_FILE: /* <file> element */ #if 0 /* some debug info - for now */ fprintf(out, "%*s<!-- deferred flag: %d -->\n", indent+2, "", info->deferred); #endif #ifdef HAS_REALPATH_EXT real = realpath(info->file.name, NULL); #endif /* HAS_REALPATH_EXT */ fprintf(out, "%*s<file name=\"%s\"", indent+2, "", real ? real : info->file.name); #ifdef HAS_REALPATH_EXT if (real) free((void*) real); #endif /* HAS_REALPATH_EXT */ if (info->error == 0 && S_ISREG(info->info.st_mode) && info->info.st_size > 0) { /* optional hex information */ size_t i, end = sizeof(info->client.header); if (info->info.st_size < end) end = info->info.st_size; fprintf(out, ">"); for (i=0; i<end; ++i) fprintf(out, "%02X", info->client.header[i]); fprintf(out, "</file>\n"); } else { fprintf(out, "/>\n"); } break; case IS_HANDLE: /* <descriptor> element */ fprintf(out, "%*s<descriptor number=\"%u\"/>\n", indent+2, "", info->file.descriptor); break; default: /* this must not happen! */ fprintf(out, "%*s<!-- ERROR: No valid file info available -->\n", indent+2, ""); break; } if (info->error == 0 && info->source != IS_INVALID) { /* <stat> subrecord */ char my[32]; struct passwd* user = wrap_getpwuid(info->info.st_uid); struct group* group = wrap_getgrgid(info->info.st_gid); fprintf(out, "%*s<statinfo mode=\"0%o\"", indent+2, "", info->info.st_mode); /* Grmblftz, are we in 32bit, 64bit LFS on 32bit, or 64bit on 64 */ sizer(my, sizeof(my), sizeof(info->info.st_size), &info->info.st_size); fprintf(out, " size=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_ino), &info->info.st_ino); fprintf(out, " inode=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_nlink), &info->info.st_nlink); fprintf(out, " nlink=\"%s\"", my); sizer(my, sizeof(my), sizeof(info->info.st_blksize), &info->info.st_blksize); fprintf(out, " blksize=\"%s\"", my); /* st_blocks is new in iv-1.8 */ sizer(my, sizeof(my), sizeof(info->info.st_blocks), &info->info.st_blocks); fprintf(out, " blocks=\"%s\"", my); fprintf(out, " mtime=\"%s\"", fmtisodate(isLocal, isExtended, info->info.st_mtime, -1)); fprintf(out, " atime=\"%s\"", fmtisodate(isLocal, isExtended, info->info.st_atime, -1)); fprintf(out, " ctime=\"%s\"", fmtisodate(isLocal, isExtended, info->info.st_ctime, -1)); fprintf(out, " uid=\"%d\"", info->info.st_uid); if (user) fprintf(out, " user=\"%s\"", user->pw_name); fprintf(out, " gid=\"%d\"", info->info.st_gid); if (group) fprintf(out, " group=\"%s\"", group->gr_name); fprintf(out, "/>\n"); } /* data section from stdout and stderr of application */ if (info->source == IS_TEMP && info->error == 0 && info->info.st_size && data_section_size > 0) { size_t dsize = data_section_size; size_t fsize = info->info.st_size; fprintf(out, "%*s<data%s", indent+2, "", (fsize > dsize ? " truncated=\"true\"" : "")); if (fsize > 0) { char* data = (char*) malloc(dsize+1); int fd = dup(info->file.descriptor); fprintf(out, ">"); if (fd != -1) { /* Get the last dsize bytes of the file */ size_t offset = 0; if (fsize > dsize) { offset = fsize - dsize; } if (lseek(fd, offset, SEEK_SET) != -1) { ssize_t rsize = read(fd, data, dsize); xmlquote(out, data, rsize); } close(fd); } fprintf(out, "</data>\n"); free((void*) data); } else { fprintf(out, "/>\n"); } } fprintf(out, "%*s</%s>\n", indent, "", tag); return 0; }