From 4730666f6e044f998fa56a95049ae6cfb2a33b4e Mon Sep 17 00:00:00 2001 From: vsr Date: Tue, 15 Mar 2016 17:12:47 +0300 Subject: [PATCH] 0023255: [CEA 1543] Integrate pidof.c in Salome's sources --- src/Container/CMakeLists.txt | 1 + src/Container/SALOME_ContainerManager.cxx | 28 +- src/Container/pidof.cxx | 501 ++++++++++++++++++++++ src/Container/pidof.hxx | 9 + 4 files changed, 533 insertions(+), 6 deletions(-) create mode 100644 src/Container/pidof.cxx create mode 100644 src/Container/pidof.hxx diff --git a/src/Container/CMakeLists.txt b/src/Container/CMakeLists.txt index 530763b1e..56f5bd8cf 100755 --- a/src/Container/CMakeLists.txt +++ b/src/Container/CMakeLists.txt @@ -80,6 +80,7 @@ SET(SalomeContainer_SOURCES Container_init_python.cxx SALOME_ContainerManager.cxx Salome_file_i.cxx + pidof.cxx ) ADD_LIBRARY(SalomeContainer ${SalomeContainer_SOURCES}) diff --git a/src/Container/SALOME_ContainerManager.cxx b/src/Container/SALOME_ContainerManager.cxx index 676adc8e3..d21a6c747 100644 --- a/src/Container/SALOME_ContainerManager.cxx +++ b/src/Container/SALOME_ContainerManager.cxx @@ -28,6 +28,7 @@ #include "SALOME_ModuleCatalog.hh" #include "Basics_Utils.hxx" #include "Basics_DirUtils.hxx" +#include "pidof.hxx" #include #include #include @@ -1295,14 +1296,29 @@ std::set SALOME_ContainerManager::getpidofprogram(const std::string progr { std::set thepids; std::string tmpFile = Kernel_Utils::GetTmpFileName(); - std::string cmd; std::string thepid; - cmd = "pidof " + program + " > " + tmpFile; - SystemThreadSafe(cmd.c_str()); - std::ifstream fpi(tmpFile.c_str(),std::ios::in); - while(fpi >> thepid){ - thepids.insert(atoi(thepid.c_str())); + + char* programc = new char[program.size() + 1]; + std::copy(program.begin(), program.end(), programc); + programc[program.size()] = '\0'; + + thepids = get_pidof(programc); + delete[] programc; + + std::ofstream fi(tmpFile.c_str(), std::ios::app); + + if(fi) + { + for (std::set::iterator i = thepids.begin(); i != thepids.end(); i++) + { + pid_t pid = *i; + fi << pid; + fi << " "; + } + fi << std::endl; + fi.close(); } + return thepids; } diff --git a/src/Container/pidof.cxx b/src/Container/pidof.cxx new file mode 100644 index 000000000..584a35238 --- /dev/null +++ b/src/Container/pidof.cxx @@ -0,0 +1,501 @@ +#include "pidof.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define STATNAMELEN 15 + +/* Info about a process. */ +typedef struct proc { + char *argv0; /* Name as found out from argv[0] */ + char *argv0base; /* `basename argv[1]` */ + char *argv1; /* Name as found out from argv[1] */ + char *argv1base; /* `basename argv[1]` */ + char *statname; /* the statname without braces */ + ino_t ino; /* Inode number */ + dev_t dev; /* Device it is on */ + pid_t pid; /* Process ID. */ + int sid; /* Session ID. */ + int kernel; /* Kernel thread or zombie. */ + struct proc *next; /* Pointer to next struct. */ +} PROC; + +/* pid queue */ + +typedef struct pidq { + PROC *proc; + struct pidq *next; +} PIDQ; + +typedef struct { + PIDQ *head; + PIDQ *tail; + PIDQ *next; +} PIDQ_HEAD; + +/* List of processes. */ +PROC *plist; + +/* Did we stop all processes ? */ +int sent_sigstop; + +int scripts_too = 0; + +char *progname; /* the name of the running program */ +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +void nsyslog(int pri, char *fmt, ...); + +/* + * Malloc space, barf if out of memory. + */ +void *xmalloc(int bytes) +{ + void *p; + + if ((p = malloc(bytes)) == NULL) { + if (sent_sigstop) kill(-1, SIGCONT); + nsyslog(LOG_ERR, (char*)"out of memory"); + exit(1); + } + return p; +} + +/* + * See if the proc filesystem is there. Mount if needed. + */ +int mount_proc(void) +{ + struct stat st; + char *args[] = { + (char*)"mount", + (char*)"-t", + (char*)"proc", + (char*)"proc", + (char*)"/proc", + 0 }; + pid_t pid, rc; + int wst; + int did_mount = 0; + + /* Stat /proc/version to see if /proc is mounted. */ + if (stat("/proc/version", &st) < 0 && errno == ENOENT) { + + /* It's not there, so mount it. */ + if ((pid = fork()) < 0) { + nsyslog(LOG_ERR, (char*)"cannot fork"); + exit(1); + } + if (pid == 0) { + /* Try a few mount binaries. */ + execv("/sbin/mount", args); + execv("/bin/mount", args); + + /* Okay, I give up. */ + nsyslog(LOG_ERR, (char*)"cannot execute mount"); + exit(1); + } + /* Wait for child. */ + while ((rc = wait(&wst)) != pid) + if (rc < 0 && errno == ECHILD) + break; + if (rc != pid || WEXITSTATUS(wst) != 0) + nsyslog(LOG_ERR, (char*)"mount returned non-zero exit status"); + + did_mount = 1; + } + + /* See if mount succeeded. */ + if (stat("/proc/version", &st) < 0) { + if (errno == ENOENT) + nsyslog(LOG_ERR, (char*)"/proc not mounted, failed to mount."); + else + nsyslog(LOG_ERR, (char*)"/proc unavailable."); + exit(1); + } + + return did_mount; +} + +int readarg(FILE *fp, char *buf, int sz) +{ + int c = 0, f = 0; + + while (f < (sz-1) && (c = fgetc(fp)) != EOF && c) + buf[f++] = c; + buf[f] = 0; + + return (c == EOF && f == 0) ? c : f; +} + +/* + * Read the proc filesystem. + */ +int readproc() +{ + DIR *dir; + FILE *fp; + PROC *p, *n; + struct dirent *d; + struct stat st; + char path[256]; + char buf[256]; + char *s, *q; + unsigned long startcode, endcode; + int pid, f; + + /* Open the /proc directory. */ + if ((dir = opendir("/proc")) == NULL) { + nsyslog(LOG_ERR, (char*)"cannot opendir(/proc)"); + return -1; + } + + /* Free the already existing process list. */ + n = plist; + for (p = plist; n; p = n) { + n = p->next; + if (p->argv0) free(p->argv0); + if (p->argv1) free(p->argv1); + free(p); + } + plist = NULL; + + /* Walk through the directory. */ + while ((d = readdir(dir)) != NULL) { + + /* See if this is a process */ + if ((pid = atoi(d->d_name)) == 0) continue; + + /* Get a PROC struct . */ + p = (PROC *)xmalloc(sizeof(PROC)); + memset(p, 0, sizeof(PROC)); + + /* Open the status file. */ + snprintf(path, sizeof(path), "/proc/%s/stat", d->d_name); + + /* Read SID & statname from it. */ + if ((fp = fopen(path, "r")) != NULL) { + buf[0] = 0; + fgets(buf, sizeof(buf), fp); + + /* See if name starts with '(' */ + s = buf; + while (*s != ' ') s++; + s++; + if (*s == '(') { + /* Read program name. */ + q = strrchr(buf, ')'); + if (q == NULL) { + p->sid = 0; + nsyslog(LOG_ERR, + (char*)"can't get program name from %s\n", + path); + free(p); + continue; + } + s++; + } else { + q = s; + while (*q != ' ') q++; + } + *q++ = 0; + while (*q == ' ') q++; + p->statname = (char *)xmalloc(strlen(s)+1); + strcpy(p->statname, s); + + /* Get session, startcode, endcode. */ + startcode = endcode = 0; + if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u " + "%*u %*u %*u %*u %*u %*d %*d " + "%*d %*d %*d %*d %*u %*u %*d " + "%*u %lu %lu", + &p->sid, &startcode, &endcode) != 3) { + p->sid = 0; + nsyslog(LOG_ERR, (char*)"can't read sid from %s\n", + path); + free(p); + continue; + } + if (startcode == 0 && endcode == 0) + p->kernel = 1; + fclose(fp); + } else { + /* Process disappeared.. */ + free(p); + continue; + } + + snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name); + if ((fp = fopen(path, "r")) != NULL) { + + /* Now read argv[0] */ + f = readarg(fp, buf, sizeof(buf)); + + if (buf[0]) { + /* Store the name into malloced memory. */ + p->argv0 = (char *)xmalloc(f + 1); + strcpy(p->argv0, buf); + + /* Get a pointer to the basename. */ + p->argv0base = strrchr(p->argv0, '/'); + if (p->argv0base != NULL) + p->argv0base++; + else + p->argv0base = p->argv0; + } + + /* And read argv[1] */ + while ((f = readarg(fp, buf, sizeof(buf))) != EOF) + if (buf[0] != '-') break; + + if (buf[0]) { + /* Store the name into malloced memory. */ + p->argv1 = (char *)xmalloc(f + 1); + strcpy(p->argv1, buf); + + /* Get a pointer to the basename. */ + p->argv1base = strrchr(p->argv1, '/'); + if (p->argv1base != NULL) + p->argv1base++; + else + p->argv1base = p->argv1; + } + + fclose(fp); + + } else { + /* Process disappeared.. */ + free(p); + continue; + } + + /* Try to stat the executable. */ + snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name); + if (stat(path, &st) == 0) { + p->dev = st.st_dev; + p->ino = st.st_ino; + } + + /* Link it into the list. */ + p->next = plist; + plist = p; + p->pid = pid; + } + closedir(dir); + + /* Done. */ + return 0; +} + +PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q) +{ + q->head = q->next = q->tail = NULL; + return q; +} + +int empty_q(PIDQ_HEAD *q) +{ + return (q->head == NULL); +} + +int add_pid_to_q(PIDQ_HEAD *q, PROC *p) +{ + PIDQ *tmp; + + tmp = (PIDQ *)xmalloc(sizeof(PIDQ)); + + tmp->proc = p; + tmp->next = NULL; + + if (empty_q(q)) { + q->head = tmp; + q->tail = tmp; + } else { + q->tail->next = tmp; + q->tail = tmp; + } + return 0; +} + +PROC *get_next_from_pid_q(PIDQ_HEAD *q) +{ + PROC *p; + PIDQ *tmp = q->head; + + if (!empty_q(q)) { + p = q->head->proc; + q->head = tmp->next; + free(tmp); + return p; + } + + return NULL; +} + +/* Try to get the process ID of a given process. */ +PIDQ_HEAD *pidof(char *prog) +{ + PROC *p; + PIDQ_HEAD *q; + struct stat st; + char *s; + int dostat = 0; + int foundone = 0; + int ok = 0; + + /* Try to stat the executable. */ + if (prog[0] == '/' && stat(prog, &st) == 0) dostat++; + + /* Get basename of program. */ + if ((s = strrchr(prog, '/')) == NULL) + s = prog; + else + s++; + + q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD)); + q = init_pid_q(q); + + /* First try to find a match based on dev/ino pair. */ + if (dostat) { + for (p = plist; p; p = p->next) { + if (p->dev == st.st_dev && p->ino == st.st_ino) { + add_pid_to_q(q, p); + foundone++; + } + } + } + + /* If we didn't find a match based on dev/ino, try the name. */ + if (!foundone) for (p = plist; p; p = p->next) { + ok = 0; + + /* Compare name (both basename and full path) */ + ok += (p->argv0 && strcmp(p->argv0, prog) == 0); + ok += (p->argv0 && strcmp(p->argv0base, s) == 0); + + /* For scripts, compare argv[1] as well. */ + if (scripts_too && p->argv1 && + !strncmp(p->statname, p->argv1base, STATNAMELEN)) { + ok += (strcmp(p->argv1, prog) == 0); + ok += (strcmp(p->argv1base, s) == 0); + } + + /* + * if we have a space in argv0, process probably + * used setproctitle so try statname. + */ + if (strlen(s) <= STATNAMELEN && + (p->argv0 == NULL || + p->argv0[0] == 0 || + strchr(p->argv0, ' '))) { + ok += (strcmp(p->statname, s) == 0); + } + if (ok) add_pid_to_q(q, p); + } + + return q; +} + +/* Give usage message and exit. */ +void usage(void) +{ + nsyslog(LOG_ERR, (char*)"only one argument, a signal number, allowed"); + closelog(); + exit(1); +} + +/* write to syslog file if not open terminal */ +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +void nsyslog(int pri, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + + if (ttyname(0) == NULL) { + vsyslog(pri, fmt, args); + } else { + fprintf(stderr, "%s: ",progname); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + } + + va_end(args); +} + +#define PIDOF_SINGLE 0x01 +#define PIDOF_OMIT 0x02 + +#define PIDOF_OMITSZ 5 + +/* + * Pidof functionality. + */ +std::set get_pidof(char *argv) +{ + PIDQ_HEAD *q; + PROC *p; + pid_t opid[PIDOF_OMITSZ], spid; + int first = 1; + int i, oind, flags = 0; + std::set lPid; + + for (oind = PIDOF_OMITSZ-1; oind > 0; oind--) + opid[oind] = 0; + opterr = 0; + + /* Print out process-ID's one by one. */ + readproc(); + //for(f = 0; f < argc; f++) { + //printf("%s",argv); + if ((q = pidof(argv)) != NULL) { + spid = 0; + while ((p = get_next_from_pid_q(q))) { + if (flags & PIDOF_OMIT) { + for (i = 0; i < oind; i++) + if (opid[i] == p->pid) + break; + /* + * On a match, continue with + * the for loop above. + */ + if (i < oind) + continue; + } + if (flags & PIDOF_SINGLE) { + if (spid) + continue; + else + spid = 1; + } + + lPid.insert(p->pid); + first = 0; + } + return lPid; + } + //} + + closelog(); + std::set lPid_empty; + return lPid_empty; +} diff --git a/src/Container/pidof.hxx b/src/Container/pidof.hxx new file mode 100644 index 000000000..54aed5c80 --- /dev/null +++ b/src/Container/pidof.hxx @@ -0,0 +1,9 @@ +#ifndef __PIDOF_HXX__ +#define __PIDOF_HXX__ + +#include +#include + +std::set get_pidof(char *argv); + +#endif -- 2.39.2