http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/_psimodule.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/_psimodule.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/_psimodule.c new file mode 100644 index 0000000..2979103 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/_psimodule.c @@ -0,0 +1,389 @@ +/* The MIT License + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** The _psi module + * + * This module contains the PsiExc_* exceptions. + * + * Additionally it currently holds the loadavg() function. + */ + + +#include <Python.h> + +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 +#include <zone.h> +#endif + +#include "psi.h" +#include "psifuncs.h" + + +/* Declarations (we need these since we use -Wmissing-declarations) */ +#ifdef PY3K +PyMODINIT_FUNC PyInit__psi(void); +#else +PyMODINIT_FUNC init_psi(void); +#endif + +/* Re-declare these as non-extern since we're providing the symbols */ +PyObject *PsiExc_AttrNotAvailableError = NULL; +PyObject *PsiExc_AttrInsufficientPrivsError = NULL; +PyObject *PsiExc_AttrNotImplementedError = NULL; +PyObject *PsiExc_MissingResourceError = NULL; +PyObject *PsiExc_InsufficientPrivsError = NULL; + + +/* More constants */ +static char MODULE_NAME[] = "psi._psi"; + + +/* Module functions */ + + +PyDoc_STRVAR(psi_boottime__doc, "\ +boottime() -> float\n\ +\n\ +Return the boot time of the of the machine as a datetime.datetime object.\n\ +"); +static PyObject * +psi_boottime(PyObject *self, PyObject *args) +{ + struct timespec boottime; + + if (arch_boottime(&boottime) < 0) + return NULL; + return PsiTimeSpec_New(&boottime); +} + + +PyDoc_STRVAR(psi_loadavg__doc, "\ +loadavg() -> (float, float, float)\n\ +\n\ +Return the number of processes in the system run queue\n\ +averaged over the last 1, 5, and 15 minutes.\n\ +"); +static PyObject * +psi_loadavg(PyObject *self, PyObject *args) +{ + struct loadavginfo* loadi; + PyObject *tuple = NULL; + PyObject *l = NULL; + + loadi = arch_loadavginfo(); + if (loadi == NULL) + return NULL; + if (psi_checkattr("loadavg()", loadi->loadavg_status) == -1) + goto cleanup; + tuple = PyTuple_New(3); + if (tuple == NULL) + goto cleanup; + l = PyFloat_FromDouble(loadi->one); + if (l == NULL) + goto cleanup; + if (PyTuple_SetItem(tuple, 0, l) == -1) + goto cleanup; + l = PyFloat_FromDouble(loadi->five); + if (l == NULL) + goto cleanup; + if (PyTuple_SetItem(tuple, 1, l) == -1) + goto cleanup; + l = PyFloat_FromDouble(loadi->fifteen); + if (l == NULL) + goto cleanup; + if (PyTuple_SetItem(tuple, 2, l) == -1) + goto cleanup; + psi_free(loadi); + return tuple; + + cleanup: + psi_free(loadi); + Py_XDECREF(tuple); + Py_XDECREF(l); + return NULL; +} + + +PyDoc_STRVAR(psi_uptime__doc, "\ +uptime() -> float\n\ +\n\ +Return the system uptime as a datetime.timedelta object.\n\ +"); +static PyObject * +psi_uptime(PyObject *self, PyObject *args) +{ + struct timespec uptime; + + if (arch_uptime(&uptime) < 0) + return NULL; + return PsiTimeSpec_New(&uptime); +} + + +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 +PyDoc_STRVAR(psi_getzoneid__doc, "\ +getzoneid() -> int\n\ +\n\ +Return the zone ID of the current python process.\n\ +"); +static PyObject * +psi_getzoneid(PyObject *self, PyObject *args) +{ + zoneid_t id; + + id = getzoneid(); + if (id < 0) + return PyErr_SetFromErrno(PyExc_OSError); + return PyLong_FromLong(id); +} + + +PyDoc_STRVAR(psi_getzoneidbyname__doc, "\ +getzoneidbyname(string) -> int\n\ +\n\ +Return the zone ID from a zone name, raise a ValueError in\n\ +case of an invalid name.\n\ +"); +static PyObject * +psi_getzoneidbyname(PyObject *self, PyObject *args) +{ + zoneid_t id; + char *name; + + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + id = getzoneidbyname(name); + if (id < 0) + return PyErr_SetFromErrno(PyExc_ValueError); + return PyLong_FromLong(id); +} + + +PyDoc_STRVAR(psi_getzonenamebyid__doc, "\ +getzonenamebyid(int) -> string\n\ +\n\ +Return the zone name from a zone ID, raise a ValueError in\n\ +case of an invalid ID.\n\ +"); +static PyObject * +psi_getzonenamebyid(PyObject *self, PyObject *args) +{ + zoneid_t id; + char name[ZONENAME_MAX]; + + if (!PyArg_ParseTuple(args, "i", &id)) + return NULL; + if (getzonenamebyid(id, name, ZONENAME_MAX) < 0) + return PyErr_SetFromErrno(PyExc_ValueError); + return PyStr_FromString(name); +} +#endif /* defined(SUNOS5 && SUNOS5_MINOR >= 10 */ + + + +/***** Module creation functions *****/ + + +/** Create a new exception class with __doc__ set. + * + * If successful, the new exception class is returned. Otherwise NULL is + * returned. +*/ +static PyObject * +create_exception(char *name, PyObject *base, const char *doc) +{ + PyObject *dict; + PyObject *docstr; + PyObject *error; + int r; + + docstr = PyStr_FromString(doc); + if (docstr == NULL) + return NULL; + dict = PyDict_New(); + if (dict == NULL) { + Py_DECREF(docstr); + return NULL; + } + r = PyDict_SetItemString(dict, "__doc__", docstr); + Py_DECREF(docstr); + if (r == -1) { + Py_DECREF(dict); + return NULL; + } + error = PyErr_NewException(name, base, dict); + Py_DECREF(dict); + return error; +} + + +/** Initialise the global exceptions + * + * If this function fails the modinit function will Py_XDECREF the exceptions, + * so no need to do that here. + */ +static int +init_exceptions(void) +{ + PsiExc_AttrNotAvailableError = create_exception( + "psi.AttrNotAvailableError", + PyExc_AttributeError, + "Requested attribute is not available for this process\n\n" + "This is a subclass of AttributeError."); + if (PsiExc_AttrNotAvailableError == NULL) + return -1; + PsiExc_AttrInsufficientPrivsError = create_exception( + "psi.AttrInsufficientPrivsError", + PyExc_AttributeError, + "Insufficient privileges for requested attribute\n\n" + "This is a subclass of AttributeError."); + if (PsiExc_AttrInsufficientPrivsError == NULL) + return -1; + PsiExc_AttrNotImplementedError = create_exception( + "psi.AttrNotImplementedError", + PyExc_AttributeError, + "Attribute has not been implemented on this system\n\n" + "This is a subclass of AttributeError."); + if (PsiExc_AttrNotImplementedError == NULL) + return -1; + PsiExc_MissingResourceError = create_exception( + "psi.MissingResourceError", + NULL, + "A resource is missing, base exception within psi."); + if (PsiExc_MissingResourceError == NULL) + return -1; + PsiExc_InsufficientPrivsError = create_exception( + "psi.InsufficientPrivsError", + NULL, + "Insufficient privileges for requested operation."); + if (PsiExc_InsufficientPrivsError == NULL) + return -1; + return 0; +} + + +static int +add_module_objects(PyObject *mod) +{ + if (PyModule_AddObject(mod, "AttrNotAvailableError", + PsiExc_AttrNotAvailableError) < 0) + return -1; + if (PyModule_AddObject(mod, "AttrInsufficientPrivsError", + PsiExc_AttrInsufficientPrivsError) < 0) + return -1; + if (PyModule_AddObject(mod, "AttrNotImplementedError", + PsiExc_AttrNotImplementedError) < 0) + return -1; + if (PyModule_AddObject(mod, "MissingResourceError", + PsiExc_MissingResourceError) < 0) + return -1; + if (PyModule_AddObject(mod, "InsufficientPrivsError", + PsiExc_InsufficientPrivsError) < 0) + return -1; + if (PyModule_AddObject(mod, "TimeSpec", (PyObject *)&PsiTimeSpec_Type) < 0) + return -1; + return 0; +} + + +static PyMethodDef psi_methods[] = { + {"boottime", psi_boottime, METH_NOARGS, psi_boottime__doc}, + {"loadavg", psi_loadavg, METH_NOARGS, psi_loadavg__doc}, + {"uptime", psi_uptime, METH_NOARGS, psi_uptime__doc}, +#if defined(SUNOS5) && SUNOS5_MINOR >= 10 + {"getzoneid", psi_getzoneid, METH_NOARGS, psi_getzoneid__doc}, + {"getzoneidbyname", psi_getzoneidbyname, METH_VARARGS, + psi_getzoneidbyname__doc}, + {"getzonenamebyid", psi_getzonenamebyid, METH_VARARGS, + psi_getzonenamebyid__doc}, +#endif + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +#ifdef PY3K +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, /* m_base */ + MODULE_NAME, /* m_name */ + 0, /* m_doc */ + -1, /* m_size */ + psi_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif + + +/* Some defines to make the module init function readable */ +#ifdef PY3K +#define MODFUNC PyInit__psi +#define RETURN(VAR) return VAR +#else +#define MODFUNC init_psi +#define RETURN(VAR) return +#endif + + +/* Returns the psi._psi module */ +PyMODINIT_FUNC +MODFUNC(void) +{ + PyObject *c_api = NULL; + PyObject *mod = NULL; + + if (PyType_Ready(&PsiTimeSpec_Type) < 0) + RETURN(NULL); + Py_INCREF(&PsiTimeSpec_Type); + if (init_exceptions() < 0) + goto error; +#ifdef PY3K + mod = PyModule_Create(&moduledef); +#else + mod = Py_InitModule(MODULE_NAME, psi_methods); +#endif + if (mod == NULL) + goto error; + if (add_module_objects(mod) < 0) + goto error; + c_api = PyCObject_FromVoidPtr((void*)PsiTimeSpec_InternalNew, NULL); + if (c_api == NULL) + goto error; + if (PyModule_AddObject(mod, "_C_API", c_api) < 0) + goto error; + RETURN(mod); + + error: + Py_DECREF(&PsiTimeSpec_Type); + Py_XDECREF(mod); + Py_XDECREF(PsiExc_AttrNotAvailableError); + Py_XDECREF(PsiExc_AttrInsufficientPrivsError); + Py_XDECREF(PsiExc_AttrNotImplementedError); + Py_XDECREF(PsiExc_MissingResourceError); + Py_XDECREF(c_api); + RETURN(NULL); +}
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch.c new file mode 100644 index 0000000..12e6f80 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch.c @@ -0,0 +1,561 @@ +/* The MIT License + * + * Copyright (C) 2007 Chris Miles + * + * Copyright (C) 2008-2009 Floris Bruynooghe + * + * Copyright (C) 2008-2009 Abilisoft Ltd. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** psi.arch.Arch* classes + * + * This file contains the common support for the psi.arch.Arch classes and + * factory functions. + */ + + +#include <Python.h> + +#include <errno.h> +#include <stdlib.h> + +#include "psi.h" +#include "arch.h" + + +#define RELEASE_INFO_SIZE 5 + + +/***** The Python ArchBase object *****/ +typedef struct { + PyObject_HEAD + struct psi_archinfo *archi; + int release_info[RELEASE_INFO_SIZE]; /* release_info tuple */ + int release_info_size; /* number of entries in release_info */ +} PsiArchBaseObject; + + +/***** Helper functions *****/ + + +void * +psi_free_archinfo(struct psi_archinfo *archi) +{ + psi_FREE(archi->sysname); + psi_FREE(archi->release); + psi_FREE(archi->version); + psi_FREE(archi->machine); + psi_FREE(archi->nodename); + psi_free(archi); + return NULL; +} + + +/** Parse a relase string into a release_info tuple + * + * This function will try to parse the release string into an array of + * integers. Roughly equivalent to this python code: [int(i) for i in + * release.split('-')[0].split('.')] + * + * @param release_info: The array to store the result into. + * @param size: The size of the array. + * @param release: The release string. + * + * @returns The number of items set in `release_info', -1 on failure. + */ +static int +set_release_info(int *release_info, const int size, const char *release) +{ + char *reldup; + char *relpart; + char *p; + int i = 0; + + reldup = psi_strdup(release); + relpart = reldup; + if (relpart == NULL) { + psi_free(reldup); + return -1; + } + p = strchr(relpart, '-'); + if (p != NULL) + *p = '\0'; + p = strchr(relpart, '.'); + while (p != NULL) { + *p++ = '\0'; + errno = 0; + release_info[i] = (int)strtol(relpart, (char**)NULL, 10); + if (errno != 0) { + PyErr_Format(PyExc_ValueError, + "Failed to parse release string '%s' into a tuple: %s", + release, strerror(errno)); + psi_free(reldup); + return -1; + } + relpart = p; + p = strchr(relpart, '.'); + i++; + if (i == size) { + PyErr_Format(PyExc_OverflowError, + "More then %d parts in release string '%s'", + size, release); + psi_free(reldup); + return -1; + } + } + errno = 0; + release_info[i] = (int)strtol(relpart, (char**)NULL, 10); + psi_free(reldup); + if (errno != 0) { + PyErr_Format(PyExc_ValueError, + "Failed to parse '%s' into a tuple: %s", + release, strerror(errno)); + return -1; + } + return i + 1; +} + + +/***** ArchBase methods *****/ + + +/** ArchBase .__new__() method + * + * This method implements singleton support by always returning the same + * object. + * + * The Py_XINCREF() each time may seem wrong but when checking the reference + * counts in a debug Python build they appear correct (and if you don't do + * this you get a negative reference count at some point). + */ +static PyObject * +ArchBase_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static PsiArchBaseObject *self = NULL; + + if (args != NULL && PySequence_Length(args) > 0) { + PyErr_Format(PyExc_TypeError, + "__new__() takes no arguments (%d given)", + (int)PySequence_Length(args)); + return NULL; + } + if (kwds != NULL && PyMapping_Length(kwds) > 0) { + PyErr_SetString(PyExc_TypeError, + "__new__() takes no keyword arguments"); + return NULL; + } + if (self == NULL) { + self = (PsiArchBaseObject *)type->tp_alloc(type, 0); + self->archi = psi_arch_archinfo(); + if (self->archi == NULL) + return NULL; + if (self->archi->release_status == PSI_STATUS_OK) { + self->release_info_size = set_release_info(self->release_info, + RELEASE_INFO_SIZE, + self->archi->release); + if (self->release_info_size < 0) + PyErr_Clear(); + } + } + Py_XINCREF(self); + return (PyObject *)self; +} + + +static void +ArchBase_dealloc(PsiArchBaseObject *self) +{ + if (self->archi != NULL) + psi_free_archinfo(self->archi); + Py_TYPE(self)->tp_free((PyObject*)self); +} + + +static PyObject * +ArchBase_repr(PsiArchBaseObject *self) +{ + return PyStr_FromFormat("%s()", Py_TYPE(self)->tp_name); +} + + +static PyObject * +ArchBase_get_sysname(PsiArchBaseObject *self, void *closure) +{ + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.sysname", self->archi->sysname_status) == -1) + return NULL; + return PyStr_FromString(self->archi->sysname); +} + + +static PyObject * +ArchBase_get_release(PsiArchBaseObject *self, void *closure) +{ + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.release", self->archi->release_status) == -1) + return NULL; + return PyStr_FromString(self->archi->release); +} + + +static PyObject * +ArchBase_get_release_info(PsiArchBaseObject *self, void *closure) +{ + PyObject *tuple; + PyObject *item; + Py_ssize_t i = (Py_ssize_t)self->release_info_size; + Py_ssize_t j; + + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.release_info", self->archi->release_status) < 0) + return NULL; + if (self->release_info_size < 0) { + PyErr_SetString(PsiExc_AttrNotAvailableError, + "release_info not available on this platform"); + return NULL; + } + tuple = PyTuple_New(i); + if (tuple == NULL) + return NULL; + for (j = 0; j < i; j++) { + item = PyLong_FromLong((long)self->release_info[j]); + if (item == NULL) { + Py_DECREF(tuple); + return NULL; + } + PyTuple_SET_ITEM(tuple, j, item); + } + return tuple; +} + + +static PyObject * +ArchBase_get_version(PsiArchBaseObject *self, void *closure) +{ + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.version", self->archi->version_status) == -1) + return NULL; + return PyStr_FromString(self->archi->version); +} + + +static PyObject * +ArchBase_get_machine(PsiArchBaseObject *self, void *closure) +{ + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.machine", self->archi->machine_status) == -1) + return NULL; + return PyStr_FromString(self->archi->machine); +} + + +static PyObject * +ArchBase_get_nodename(PsiArchBaseObject *self, void *closure) +{ + if (self->archi == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Instance has not been initialised properly"); + return NULL; + } + if (psi_checkattr("Arch.nodename", self->archi->nodename_status) == -1) + return NULL; + return PyStr_FromString(self->archi->nodename); +} + + +static PyGetSetDef ArchBase_getseters[] = { + {"sysname", (getter)ArchBase_get_sysname, (setter)NULL, + "Name of the operating system implementation", NULL}, + {"release", (getter)ArchBase_get_release, (setter)NULL, + "Release level of the operating system", NULL}, + {"release_info", (getter)ArchBase_get_release_info, (setter)NULL, + "Tuple representation of the operating system release level", NULL}, + {"version", (getter)ArchBase_get_version, (setter)NULL, + "Version level of the operating system", NULL}, + {"machine", (getter)ArchBase_get_machine, (setter)NULL, + "Machine hardware platform", NULL}, + {"nodename", (getter)ArchBase_get_nodename, (setter)NULL, + "Network name of the machine", NULL}, + {NULL} /* Sentinel */ +}; + + +PyTypeObject PsiArchBase_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.arch.ArchBase", /* tp_name */ + sizeof(PsiArchBaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)ArchBase_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)ArchBase_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Base object for all arch classes", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + ArchBase_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)ArchBase_new, /* tp_new */ +}; + + +PyTypeObject PsiArchDarwin_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.arch.ArchDarwin", /* tp_name */ + sizeof(PsiArchBaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "This object represents a Darwin system", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PsiArchBase_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +PyTypeObject PsiArchSunOS_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.arch.ArchSunOS", /* tp_name */ + sizeof(PsiArchBaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "This object represnets a SunOS system", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PsiArchBase_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +PyTypeObject PsiArchLinux_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.arch.ArchLinux", /* tp_name */ + sizeof(PsiArchBaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "This object represents a Linux system", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PsiArchBase_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +PyTypeObject PsiArchAIX_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "psi.arch.ArchAIX", /* tp_name */ + sizeof(PsiArchBaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "This object represents an AIX system", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PsiArchBase_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + +/* Object Creation Functions */ + + +PyObject * +PsiArchBase_New(void) +{ + return ArchBase_new(&PsiArchBase_Type, NULL, NULL); +} + + +PyObject * +PsiArch_New(void) +{ +#ifdef DARWIN + return ArchBase_new(&PsiArchDarwin_Type, NULL, NULL); +#elif SUNOS + return ArchBase_new(&PsiArchSunOS_Type, NULL, NULL); +#elif LINUX + return ArchBase_new(&PsiArchLinux_Type, NULL, NULL); +#elif AIX + return ArchBase_new(&PsiArchAIX_Type, NULL, NULL); +#else +# error "Unknown system, can't compile" +#endif +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_mount.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_mount.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_mount.c new file mode 100644 index 0000000..f6b6693 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_mount.c @@ -0,0 +1,189 @@ +/* The MIT License + * + * Copyright (C) 2009 Floris Bruynooghe + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +#include <Python.h> + +#include <string.h> +#include <sys/types.h> +#include <sys/mntctl.h> +#include <sys/vmount.h> + +#include "psi.h" +#include "mount.h" +#include "posix_mount.h" + + +/***** Local declarations *****/ + +static int set_vmount(psi_mountinfo_t *mounti, const struct vmount *mnt); +static char *map_fstype(const int gfstype); + + +/***** Public functions *****/ + +psi_mountlist_t * +psi_arch_mountlist(const int remote) +{ + psi_mountlist_t *ml; + psi_mountinfo_t *mounti; + struct vmount *mnt; + char *vmounts; + int vmounts_size = sizeof(struct vmount); + int nmounts; + int offset = 0; + int i; + + vmounts = psi_malloc(vmounts_size); + if (vmounts == NULL) + return NULL; + nmounts = mntctl(MCTL_QUERY, vmounts_size, vmounts); + if (nmounts == 0) { + mnt = (struct vmount *)vmounts; + vmounts_size = mnt->vmt_revision; + psi_free(vmounts); + vmounts = psi_malloc(vmounts_size); + if (vmounts == NULL) + return NULL; + nmounts = mntctl(MCTL_QUERY, vmounts_size, vmounts); + } + if (nmounts == -1) { + psi_free(vmounts); + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } else if (nmounts == 0) { + psi_free(vmounts); + PyErr_SetString(PyExc_OSError, "Internal race condition"); + return NULL; + } + ml = (psi_mountlist_t *)psi_calloc(sizeof(psi_mountlist_t)); + if (ml == NULL) { + psi_free(vmounts); + return NULL; + } + ml->mounts = (psi_mountinfo_t **)psi_calloc( + nmounts*sizeof(psi_mountinfo_t *)); + if (ml->mounts == NULL) { + psi_free(vmounts); + psi_free(ml); + return NULL; + } + ml->count = 0; + for (i = 0; i < nmounts; i++) { + mnt = (struct vmount *)(vmounts + offset); + if (!remote && strcmp(vmt2dataptr(mnt, VMT_HOST), "-") != 0) + continue; + mounti = psi_calloc(sizeof(psi_mountinfo_t)); + ml->mounts[ml->count] = mounti; + ml->count += 1; + if (set_vmount(mounti, mnt) < 0) { + psi_free(vmounts); + psi_free_mountlist(ml); + return NULL; + } + if (posix_set_vfs(mounti) < 0) { + psi_free(vmounts); + psi_free_mountlist(ml); + return NULL; + } + } + return ml; +} + + +/***** Local Functions *****/ + + +#define STRDUP(dst, src) \ + if ((dst = psi_strdup(src)) == NULL) \ + return -1; \ + dst ## _status = PSI_STATUS_OK + + +static int +set_vmount(psi_mountinfo_t *mounti, const struct vmount *mnt) +{ + mounti->mount_type = map_fstype(mnt->vmt_gfstype); + if (mounti->mount_type == NULL) + return -1; + mounti->mount_type_status = PSI_STATUS_OK; + + /* XXX Debatable, options should maybe be flags instead of args. */ + STRDUP(mounti->mount_options, vmt2dataptr(mnt, VMT_ARGS)); + STRDUP(mounti->mount_path, vmt2dataptr(mnt, VMT_STUB)); + if (strcmp(vmt2dataptr(mnt, VMT_HOST), "-") != 0) + STRDUP(mounti->filesystem_host, vmt2dataptr(mnt, VMT_HOST)); + STRDUP(mounti->filesystem_path, vmt2dataptr(mnt, VMT_OBJECT)); + return 0; +} + + +/** Convert struct vmount member vmt_gfstype into string + * + * This is a hardcoded list currently, that seems to be the only way it's + * defined/available on AIX. + */ +static char * +map_fstype(const int gfstype) +{ + char *type; + + switch (gfstype) { + case MNT_J2: + return psi_strdup("jfs2"); + case MNT_NAMEFS: + return psi_strdup("namefs"); + case MNT_NFS: + return psi_strdup("nfs"); + case MNT_JFS: + return psi_strdup("jfs"); + case MNT_CDROM: + return psi_strdup("cdrom"); + case MNT_PROCFS: + return psi_strdup("proc"); + case MNT_SFS: + return psi_strdup("STREAM"); + case MNT_CACHEFS: + return psi_strdup("cachefs"); + case MNT_NFS3: + return psi_strdup("NFSv3"); + case MNT_AUTOFS: + return psi_strdup("automount"); + case MNT_VXFS: + return psi_strdup("vxfs"); + case MNT_VXODM: + return psi_strdup("veritas"); + case MNT_UDF: + return psi_strdup("UDFS"); + case MNT_NFS4: + return psi_strdup("NFSv4"); + case MNT_RFS4: + return psi_strdup("NFSv4-pseudo"); + case MNT_CIFS: + return psi_strdup("SMBFS"); + default: + psi_asprintf(&type, "%d", gfstype); + return type; + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_process.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_process.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_process.c new file mode 100644 index 0000000..8e64150 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_process.c @@ -0,0 +1,597 @@ +/* The MIT License + * + * Copyright (C) 2009 Floris Bruynooghe + * + * Copyright (C) 2009 Abilisoft Ltd. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* AIX implementation of the Process classes */ + + +/* Note: On AIX if __64BIT__ is defined the LP64 data model is used, otherwise + * ILP23 is used. + * + * Note2: We use large file APIs to read the core files of processes (aka + * address space, /proc/<pid>/as), read up on large file support: + * http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/prg_lrg_files.htm */ + + +#include <Python.h> + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <procinfo.h> +#include <stdio.h> +#include <string.h> +#include <sys/dir.h> +#include <sys/proc.h> +#include <sys/procfs.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include "psi.h" +#include "process.h" +#include "posix_utils.h" +#include "procfs_utils.h" + + +/***** Local declarations *****/ +static int getprocent(struct procentry64 *procbuff, const pid_t pid); +static int set_bulk(struct psi_process *proci, + const struct procentry64 *procent); +static int set_args(struct psi_process *proci, + struct procentry64 *procent); +static int set_env(struct psi_process *proci, + struct procentry64 *procent); +static int set_cwd(struct psi_process *proci, + const struct procentry64 *procent); + +static int get_terminal(const dev64_t ttydev, char **name); +static int is_tty_file(struct dirent *dirp); +static void free_dentlist(struct dirent **dentlist, const int ndirs); +static int mygetargs(struct procentry64 *procbuff, char **args); +static int args_complete(char *args, const int size); +static int mygetevars(struct procentry64 *procent, char **evnp); + + +/***** Declare undeclared functions from <procinfo.h> *****/ +/* IMHO <procinfo.h> should declare these, see getprocs(3) and getargs(3) */ +extern int getprocs64(struct procentry64*, int, + struct fdsinfo64*, int, pid32_t*, int); +extern int getargs(struct procentry64*, int, char*, int); +extern int getevars(struct procentry64*, int, char*, int); + + +/***** Public interfaces from process.h. *****/ + + +/* The process status flags, defined in proc.h. */ +/* XXX Might have to use lwpsinfo.sname instead */ +#define addsflag(CONST) {"PROC_STATUS_"#CONST, CONST} +struct psi_flag psi_arch_proc_status_flags[] = { + addsflag(SNONE), + addsflag(SIDL), + addsflag(SZOMB), + addsflag(SSTOP), + addsflag(SACTIVE), + addsflag(SSWAP), + {NULL, 0} +}; + + +/** Collect all information about a process + * + * The psinfo variable is so that /proc/<pid>/psinfo only needs to be read + * once. + */ +struct psi_process * +psi_arch_process(const pid_t pid) +{ + struct psi_process *proci; + struct procentry64 procent; + int r; + + r = getprocent(&procent, pid); + if (r < 0) + return NULL; + proci = psi_calloc(sizeof(struct psi_process)); + if (proci == NULL) + return NULL; + if (set_bulk(proci, &procent) < 0) + return psi_free_process(proci); + if (set_args(proci, &procent) < 0) + return psi_free_process(proci); + if (set_env(proci, &procent) < 0) + return psi_free_process(proci); + if (set_cwd(proci, &procent) < 0) + return psi_free_process(proci); + return proci; +} + + +/***** Local functions *****/ + + +/** Call getprocs64(3) for exactly 1 PID + * + * This takes care of boring details and handles errors properly. + * + * @param procbuff: the procentry64 structure the result will be stored in. + * @param pid: the PID of the process to get. + * + * @return -1 in case of an error, 0 if successful. + **/ +static int +getprocent(struct procentry64 *procbuff, const pid_t pid) +{ + pid32_t pid32; + int r; + + pid32 = (pid32_t)pid; + r = getprocs64(procbuff, sizeof(struct procentry64), + (struct fdsinfo64 *)NULL, 0, + &pid32, 1); + if (r < 0) { + if (errno == EINVAL) + PyErr_Format(PsiExc_NoSuchProcessError, + "No such PID: %lu", (unsigned long)pid); + else + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "getprocs64()"); + return -1; + } + return 0; +} + + +/** Get all data from the procentry64 structure + * + * This is a poorly named function. It gets as much data out of the + * procentry64 structure as possible and places it in the psi_process + * structure. + */ +static int +set_bulk(struct psi_process *proci, const struct procentry64 *procent) +{ + int pagesize; + int r; + + proci->name = psi_strdup(procent->pi_comm); + if (proci->name == NULL) + return -1; + proci->name_status = PSI_STATUS_OK; + proci->exe = proci->name; + proci->exe_status = PSI_STATUS_OK; + + proci->euid = procent->pi_cred.crx_uid; + proci->euid_status = PSI_STATUS_OK; + proci->ruid = procent->pi_cred.crx_ruid; + proci->ruid_status = PSI_STATUS_OK; + proci->egid = procent->pi_cred.crx_gid; + proci->egid_status = PSI_STATUS_OK; + proci->rgid = procent->pi_cred.crx_rgid; + proci->rgid_status = PSI_STATUS_OK; + + proci->ppid = procent->pi_ppid; + proci->ppid_status = PSI_STATUS_OK; + proci->pgrp = procent->pi_pgrp; + proci->pgrp_status = PSI_STATUS_OK; + proci->sid = procent->pi_sid; + proci->sid_status = PSI_STATUS_OK; + + proci->priority = procent->pi_ppri; + proci->priority_status = PSI_STATUS_OK; + proci->nice = procent->pi_nice; + proci->nice_status = PSI_STATUS_OK; + proci->start_time.tv_sec = procent->pi_start; + proci->start_time.tv_nsec = 0; + proci->start_time_status = PSI_STATUS_OK; + proci->status = procent->pi_state; + proci->status_status = PSI_STATUS_OK; + proci->nthreads = procent->pi_thcount; + proci->nthreads_status = PSI_STATUS_OK; + + r = get_terminal(procent->pi_ttyd, &proci->terminal); + if (r == -1) + return -1; + else if (r == -2) + proci->terminal_status = PSI_STATUS_PRIVS; + else + proci->terminal_status = PSI_STATUS_OK; + + /* The ru_utime and ru_stime members are `struct timeval64' which claims + * to contain microseconds in `tv_usec'. However all evidence suggests + * that it really is nanoseconds: (i) the values stored in it are larger + * then 1e6 and (ii) the results do match with ps(1) when treated as + * nanoseconds, but not when treated as micoseconds. */ + proci->utime.tv_sec = procent->pi_ru.ru_utime.tv_sec; + proci->utime.tv_nsec = procent->pi_ru.ru_utime.tv_usec; + proci->utime_status = PSI_STATUS_OK; + proci->stime.tv_sec = procent->pi_ru.ru_stime.tv_sec; + proci->stime.tv_nsec = procent->pi_ru.ru_stime.tv_usec; + proci->stime_status = PSI_STATUS_OK; + + /* There is a procent.pi_cpu which claims to be a tick count for the first + * thread, but I trust this more. */ + proci->cputime.tv_sec = proci->utime.tv_sec + proci->stime.tv_sec; + proci->cputime.tv_sec += + (proci->utime.tv_nsec + proci->stime.tv_nsec)/1000000000; + proci->cputime.tv_nsec = + (proci->utime.tv_nsec + proci->stime.tv_nsec)%1000000000; + proci->cputime_status = PSI_STATUS_OK; + + pagesize = getpagesize(); + proci->rss = (procent->pi_drss + procent->pi_trss) * pagesize; + proci->rss_status = PSI_STATUS_OK; + /* This is the same size as returned by ps(1) for VSZ. I don't believe + * it's correct however, it only contains the data sections of the virtual + * memory and omits the text size. None of the other values seem to give + * something useful either tho and there is something to be said for + * showing what ps shows. You can see the real value (in pagesizes) by + * using "svmon -P <pid>" and look in the "Virtual" column. */ + proci->vsz = procent->pi_dvm * pagesize; + proci->vsz_status = PSI_STATUS_OK; + + return 0; +} + + +static int +set_args(struct psi_process *proci, struct procentry64 *procent) +{ + char *ptr; + int i; + + proci->argc = mygetargs(procent, &proci->command); + if (proci->argc == -1) + return -1; + if (proci->argc == -2) { /* proc gone walkies */ + proci->argc_status = PSI_STATUS_NA; + proci->argv_status = PSI_STATUS_NA; + return 0; + } + proci->argv = psi_strings_to_array(proci->command, proci->argc); + if (proci->argv == NULL) + return -1; + ptr = proci->command; + for (i = 0; i < proci->argc - 1; i++) { + while (*ptr != '\0') + ptr++; + *ptr = ' '; + } + proci->argc_status = PSI_STATUS_OK; + proci->argv_status = PSI_STATUS_OK; + proci->command_status = PSI_STATUS_OK; + return 0; +} + + +static int +set_env(struct psi_process *proci, struct procentry64 *procent) +{ + char *envp; + + proci->envc = mygetevars(procent, &envp); + if (proci->envc == -1) + return -1; + if (proci->envc == -2) { /* proc gone walkies */ + proci->envc_status = PSI_STATUS_NA; + proci->envv_status = PSI_STATUS_NA; + return 0; + } + proci->envv = psi_strings_to_array(envp, proci->envc); + psi_free(envp); + if (proci->envv == NULL) + return -1; + proci->envc_status = PSI_STATUS_OK; + proci->envv_status = PSI_STATUS_OK; + return 0; +} + + +/** Set the cwd and cwd_status fields of the procinfo structure + * + * Returns -1 on failure, 0 on success. + */ +static int +set_cwd(struct psi_process *proci, const struct procentry64 *procent) +{ + char *fname; + char *link; + int r; + + r = psi_asprintf(&fname, "/proc/%d/cwd", procent->pi_pid); + if (r == -1) + return -1; + r = psi_readlink(&link, fname); + psi_free(fname); + if (r == -2) { + PyErr_Clear(); + proci->cwd_status = PSI_STATUS_PRIVS; + return 0; + } else if (r < 0) { + PyErr_Clear(); + if (procfs_check_pid(procent->pi_pid) < 0) + return -1; + else { + proci->cwd_status = PSI_STATUS_NA; + return 0; + } + } else { + proci->cwd = link; + proci->cwd_status = PSI_STATUS_OK; + return 0; + } +} + + +/** Find the name of a terminal + * + * This function will look at all files in /dev to find the matching device + * number. When found the `name' parameter will be pointed to a newly + * allocated name of the terminal, otherwise it will be set to point to NULL. + * + * Return 0 if successful, -1 in case of an error and -2 in case of a + * permission problem. + */ +/* XXX Split this off in two functions. */ +static int +get_terminal(const dev64_t ttydev, char **name) +{ + struct stat64x stat_buff; + struct dirent **dentlist; + struct dirent *dentp; + char ttyname[15] = _PATH_DEV; /* "/dev/console\0" is longest expected */ + int nfiles; + int i; + int r; + + *name = NULL; + + /* Check /dev/pts/ files */ + r = stat64x("/dev/pts/0", &stat_buff); + if (r < 0) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/dev/pts/0"); + return -1; + } + if (major64(ttydev) == major64(stat_buff.st_rdev)) { + if (minor64(ttydev) > 99) { + PyErr_SetString(PyExc_RuntimeError, + "Minor number can be no larger then 99"); + return -1; + } + sprintf(ttyname, "/dev/pts/%d", minor64(ttydev)); + *name = psi_strdup(ttyname); + if (*name == NULL) + return -1; + return 0; + } + + /* Scan for /dev/console and /dev/tty* */ + nfiles = scandir(_PATH_DEV, &dentlist, &is_tty_file, NULL); + if (nfiles < 0) { + PyErr_SetString(PyExc_OSError, "Failed to list /dev entries"); + return -1; + } + if (nfiles == 0) { + free_dentlist(dentlist, nfiles); + return 0; + } + for (i = 0; i < nfiles; i++) { + dentp = dentlist[i]; + if (strlen(ttyname) + strlen(dentp->d_name) + 1 > 15) { + PyErr_SetString(PyExc_RuntimeError, "ttyname larger then 14 chars"); + free_dentlist(dentlist, nfiles); + return -1; + } + strcat(ttyname, dentp->d_name); + r = stat64x(ttyname, &stat_buff); + if (r < 0) { + free_dentlist(dentlist, nfiles); + if (errno == EACCES) + return -2; + else { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, ttyname); + return -1; + } + } + if (ttydev == stat_buff.st_dev) { + free_dentlist(dentlist, nfiles); + *name = psi_strdup(ttyname); + if (*name == NULL) + return -1; + return 0; + } + } + free_dentlist(dentlist, nfiles); + return 0; +} + + +static int +is_tty_file(struct dirent *dirp) +{ + if (strncmp(_PATH_TTY, dirp->d_name, strlen(_PATH_TTY)) == 0) + return 1; + else if (strcmp(_PATH_CONSOLE, dirp->d_name) == 0) + return 1; + else + return 0; +} + + +static void +free_dentlist(struct dirent **dentlist, const int ndirs) +{ + int i; + + for (i = 0; i < ndirs; i++) + free(dentlist[i]); + free(dentlist); +} + + +/** Return list of process arguments, ending in `\0\0' + * + * This wraps getargs(3) but allocates the string automatically using + * psi_malloc() and guarantees the complete argument list is returned. + * + * Returns -1 in case of an error and -2 if the process is gone. On success + * the number of arguments in the argument list is returned. + */ +static int +mygetargs(struct procentry64 *procbuff, char **args) +{ +/* XXX nargs should be `usigned int' and args_sz & i `ssize_t' but getargs() + * uses int for args_sz bizzarly enough. --flub */ + char *ptr; + int size = 250; /* size of `args' */ + int nargs; + int r; + + *args = (char*)psi_malloc(size); + if (*args == NULL) + return -1; + r = getargs(procbuff, sizeof(struct procentry64), *args, size); + if (r < 0) { + psi_free(*args); + if (errno == ESRCH) /* proc gone walkies */ + return -2; + else { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "getargs()"); + return -1; + } + } + nargs = args_complete(*args, size); + while (nargs < 0) { + size += 250; + ptr = (char*)psi_realloc(*args, size); + if (ptr == NULL) { + psi_free(*args); + return -1; + } + *args = ptr; + r = getargs(procbuff, sizeof(struct procentry64), *args, size); + if (r < 0) { + psi_free(*args); + if (errno == ESRCH) /* proc gone walkies */ + return -2; + else { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "getargs()"); + return -1; + } + } + nargs = args_complete(*args, size); + } + return nargs; +} + + +/** Check if an argument list is complete + * + * This function looks for a `\0\0' in the string `args' (which is up too + * `size' characters long). If found it returns the number of `\0'-terminated + * strings, excluding the last empty one, otherwise -1 is returned. + * + * This is useful to check if a getargs(3) call returned the complete argument + * list. + */ +static int +args_complete(char *args, const int size) +{ + int complete = 0; + int nargs = 0; + int i; + + for (i = 1; i < size; i++) { + if (args[i] == '\0') { + if (args[i-1] == '\0') { + complete = 1; + break; + } else + nargs++; + } + } + if (!complete) + return -1; + else + return nargs; +} + + +/** Return list of process environment variables, ending in `\0\0' + * + * This wraps getevars(3) but allocates the string automatically using + * psi_malloc() and guarantees the complete environment is returned. + * + * Returns -1 in case of an error and -2 if the process is gone. On success + * the number of environment variables in the argument list is returned. + */ +static int +mygetevars(struct procentry64 *procent, char **envp) +{ +/* XXX `n' should be `usigned int' and args_sz & i `ssize_t' but getargs() + * uses `int' for `args_sz' bizzarly enough. --flub */ + char *ptr; + int size = 250; /* size of `envp' */ + int n; /* number of environment variables */ + int r; + + *envp = (char*)psi_malloc(size); + if (*envp == NULL) + return -1; + r = getevars(procent, sizeof(struct procentry64), *envp, size); + if (r < 0) { + psi_free(*envp); + if (errno == ESRCH) /* proc gone walkies */ + return -2; + else { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "getevars()"); + return -1; + } + } + n = args_complete(*envp, size); + while (n < 0) { + size += 250; + ptr = (char*)psi_realloc(*envp, size); + if (ptr == NULL) { + psi_free(*envp); + return -1; + } + *envp = ptr; + r = getevars(procent, sizeof(struct procentry64), *envp, size); + if (r < 0) { + psi_free(*envp); + if (errno == ESRCH) /* proc gone walkies */ + return -2; + else { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "getevars()"); + return -1; + } + } + n = args_complete(*envp, size); + } + return n; +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_psi.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_psi.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_psi.c new file mode 100644 index 0000000..09fcb15 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/aix_psi.c @@ -0,0 +1,89 @@ +/* The MIT License + * + * Copyright (C) 2009 Floris Bruynooghe + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* AIX implementation of the _psi functions */ + + +#include <Python.h> + +#include <libperfstat.h> +#include <sys/proc.h> +#include <sys/types.h> +#include <time.h> +#include <utmpx.h> + +#include "psi.h" +#include "psifuncs.h" +#include "posix_utils.h" + + +/***** Public functions *****/ + + +int +arch_boottime(struct timespec *boottime) +{ + return posix_utmpx_boottime(boottime); +} + + +struct loadavginfo * +arch_loadavginfo(void) +{ + struct loadavginfo *loadi; + perfstat_cpu_total_t cpu_stats; + int r; + + r = perfstat_cpu_total(NULL, &cpu_stats, sizeof(perfstat_cpu_total_t), 1); + if (r < 0) + return (struct loadavginfo*)PyErr_SetFromErrno(PyExc_OSError); + loadi = psi_calloc(sizeof(struct loadavginfo)); + if (loadi == NULL) + return NULL; + loadi->one = cpu_stats.loadavg[0] / (double)(1 << SBITS); + loadi->five = cpu_stats.loadavg[0] / (double)(1 << SBITS); + loadi->fifteen = cpu_stats.loadavg[0] / (double)(1 << SBITS); + loadi->loadavg_status = PSI_STATUS_OK; + return loadi; +} + + +int +arch_uptime(struct timespec *uptime) +{ + struct timespec utbt; + struct timespec now; + struct timeval tvnow; + + if (posix_utmpx_boottime(&utbt) < 0) + return -1; + if (gettimeofday(&tvnow, NULL) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + now.tv_sec = tvnow.tv_sec; + now.tv_nsec = tvnow.tv_usec * 1000; + *uptime = posix_timespec_subtract(&now, &utbt); + return 0; +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_mount.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_mount.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_mount.c new file mode 100644 index 0000000..4f965a9 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_mount.c @@ -0,0 +1,170 @@ +/* The MIT License + * + * Copyright (C) 2009 Erick Tryzelaar + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +#include <Python.h> + +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> + +#include "psi.h" +#include "mount.h" +#include "posix_mount.h" + + +/* Pulled from Apple's mount.c */ +static struct opt { + int o_opt; + const char *o_name; +} optnames[] = { + { MNT_ASYNC, "asynchronous" }, + { MNT_EXPORTED, "NFS exported" }, + { MNT_LOCAL, "local" }, + { MNT_NODEV, "nodev" }, + { MNT_NOEXEC, "noexec" }, + { MNT_NOSUID, "nosuid" }, + { MNT_QUOTA, "with quotas" }, + { MNT_RDONLY, "read-only" }, + { MNT_SYNCHRONOUS, "synchronous" }, + { MNT_UNION, "union" }, + { MNT_AUTOMOUNTED, "automounted" }, + { MNT_JOURNALED, "journaled" }, + { MNT_DEFWRITE, "defwrite" }, + { MNT_IGNORE_OWNERSHIP, "noowners" }, +#ifdef MNT_NOATIME + { MNT_NOATIME, "noatime" }, +#endif +#ifdef MNT_QUARANTINE + { MNT_QUARANTINE, "quarantine" }, +#endif + { 0, NULL } +}; + + +#define STRDUP(dst, src) \ +{ \ + if ((dst = psi_strdup(src)) == NULL) { \ + psi_free_mountlist(ml); \ + } \ + dst ## _status = PSI_STATUS_OK; \ +} + + +psi_mountlist_t * +psi_arch_mountlist(const int remote) +{ + struct statfs *mp; + int count; + psi_mountlist_t *ml = NULL; + psi_mountinfo_t *mounti, **mounts; + char *p; + + /* Get the mount info from the kernel */ + if ((count = getmntinfo(&mp, MNT_NOWAIT)) == 0) { + return (psi_mountlist_t*) PyErr_SetFromErrnoWithFilename( + PyExc_OSError, "getmntinfo failed"); + } + + /* Create our mountlist */ + ml = (psi_mountlist_t *)psi_calloc(sizeof(psi_mountlist_t)); + if (ml == NULL) { + return NULL; + } + + /* Step through each line in the mount data */ + while (--count >= 0) { + struct opt *o; + int flags; + char options[1024]; + + /* Ignore mount type autofs since that filesystem may not actually be + * mounted */ + if (strcmp(mp->f_fstypename, "autofs") == 0) { + ++mp; + continue; + } + + /* Only include a remote fs if asked for */ + if (!remote && strchr(mp->f_mntfromname, ':') != NULL) { + ++mp; + continue; + } + + /* Allocate space for the mount information */ + if ((mounti = psi_calloc(sizeof(psi_mountinfo_t))) == NULL) { + psi_free_mountlist(ml); + return NULL; + } + + /* And then allocate more space for the mount list */ + mounts = (psi_mountinfo_t **)psi_realloc( + ml->mounts, + (ml->count + 1) * sizeof(psi_mountinfo_t *)); + if (mounts == NULL) { + psi_free_mountinfo(mounti); + psi_free_mountlist(ml); + return NULL; + } + ml->mounts = mounts; + ml->mounts[ml->count] = mounti; + ml->count += 1; + + /* Finally, add all the mntent information to mounti */ + p = strchr(mp->f_mntfromname, ':'); + if (p == NULL) { + mounti->filesystem_host_status = PSI_STATUS_OK; + STRDUP(mounti->filesystem_path, mp->f_mntfromname); + } else { + *p = '\0'; + + STRDUP(mounti->filesystem_host, mp->f_mntfromname); + STRDUP(mounti->filesystem_path, p + 1); + } + + STRDUP(mounti->mount_type, mp->f_fstypename); + STRDUP(mounti->mount_path, mp->f_mntonname); + + /* Convert the flags into a string */ + flags = mp->f_flags & MNT_VISFLAGMASK; + p = options; + for (o = optnames; flags && o->o_opt; ++o) { + if (flags & o->o_opt) { + int i = snprintf(p, 1024 - (p-options), + "%s%s", p == options ? "" : ",", o->o_name); + flags &= ~o->o_opt; + p += i; + } + } + STRDUP(mounti->mount_options, options); + + /* Set the statvfs items */ + posix_set_vfs(mounti); + + /* Advance the mount pointer */ + ++mp; + } + + return ml; +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/80e25b46/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_process.c ---------------------------------------------------------------------- diff --git a/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_process.c b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_process.c new file mode 100644 index 0000000..6fe6dc6 --- /dev/null +++ b/tools/bin/pythonSrc/PSI-0.3b2_gp/src/arch/darwin_process.c @@ -0,0 +1,562 @@ +/* The MIT License + * + * Copyright (C) 2007 Chris Miles + * + * Copyright (C) 2009 Erick Tryzelaar + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Process functions for arch: Mac OS X */ + +#include <Python.h> + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/sysctl.h> +#include <sys/fcntl.h> +#include <pwd.h> +#include <grp.h> +#include <mach/shared_memory_server.h> +#include <mach/mach_init.h> +#include <mach/mach_interface.h> +#include <pwd.h> +#include <grp.h> +#include <sys/proc.h> + +#include "psi.h" +#include "psifuncs.h" +#include "process.h" + + +/***** Local declarations *****/ + +static int get_kinfo_proc(const pid_t pid, struct kinfo_proc *p); +static int set_exe(struct psi_process *proci, struct kinfo_proc *p); +static int set_cwd(struct psi_process *proci, struct kinfo_proc *p); +static int set_kp_proc(struct psi_process *proci, struct kinfo_proc *p); +static int set_kp_eproc(struct psi_process *proci, struct kinfo_proc *p); +static int set_task(struct psi_process *proci, struct kinfo_proc *p); +static int command_from_argv(char **command, char **argv, int argc); +static struct timespec calc_cputime(const struct timespec utime, + const struct timespec stime); + + +/***** Public interfaces from process.h. *****/ + +struct psi_flag psi_arch_proc_status_flags[] = { + {"PROC_STATUS_SIDL", SIDL}, + {"PROC_STATUS_SRUN", SRUN}, + {"PROC_STATUS_SSLEEP", SSLEEP}, + {"PROC_STATUS_SSTOP", SSTOP}, + {"PROC_STATUS_SZOMB", SZOMB}, + {NULL, 0}}; /* sentinel */ + + +struct psi_process * +psi_arch_process(const pid_t pid) +{ + struct kinfo_proc p; + struct psi_process *proci; + + if (get_kinfo_proc(pid, &p) == -1) { + return NULL; + } + + proci = psi_calloc(sizeof(struct psi_process)); + if (proci == NULL) { + return NULL; + } + + if (set_exe(proci, &p) == -1) goto cleanup; + if (set_cwd(proci, &p) == -1) goto cleanup; + if (set_kp_proc(proci, &p) == -1) goto cleanup; + if (set_kp_eproc(proci, &p) == -1) goto cleanup; + if (set_task(proci, &p) == -1) goto cleanup; + + if (proci->utime_status == PSI_STATUS_PRIVS || + proci->stime_status == PSI_STATUS_PRIVS) + proci->cputime_status = PSI_STATUS_PRIVS; + else { + proci->cputime = calc_cputime(proci->utime, proci->stime); + proci->cputime_status = PSI_STATUS_OK; + } + + if (proci->command_status == PSI_STATUS_PRIVS) { + /* Ensure Process.command always has a value, as per our + * contract with the user. + */ + proci->command = psi_strdup(""); + proci->command_status = PSI_STATUS_OK; + } + + return proci; + + cleanup: + psi_free_process(proci); + return NULL; +} + + +/***** Local functions *****/ + + +static int +get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) +{ + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; + size_t size; + + size = sizeof(struct kinfo_proc); + + /* We use sysctl here instead of psi_sysctl because we know the size of + * the destination already so we don't need to malloc anything. */ + if (sysctl((int*)name, 4, proc, &size, NULL, 0) == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + /* sysctl stores 0 in the size if we can't find the process information */ + if (size == 0) { + PyErr_Format(PsiExc_NoSuchProcessError, "No such PID: %ld", (long)pid); + return -1; + } + + return 0; +} + + +/** Find the executable, argument list and environment + * + * This will also fill in the command attribute. + * + * The sysctl calls here don't use a wrapper as in darwin_prcesstable.c since + * they know the size of the returned structure already. + * + * The layout of the raw argument space is documented in start.s, which is + * part of the Csu project. In summary, it looks like: + * + * XXX: This layout does not match whith what the code does. The code seems + * to think exec_path is in between the first argc and arg[0], also the data + * returned by ssyctl() seems to be starting at the first argc according to + * the code. + * + * /---------------\ 0x00000000 + * : : + * : : + * |---------------| + * | argc | + * |---------------| + * | arg[0] | + * |---------------| + * : : + * : : + * |---------------| + * | arg[argc - 1] | + * |---------------| + * | 0 | + * |---------------| + * | env[0] | + * |---------------| + * : : + * : : + * |---------------| + * | env[n] | + * |---------------| + * | 0 | + * |---------------| <-- Beginning of data returned by sysctl() is here. + * | argc | + * |---------------| + * | exec_path | + * |:::::::::::::::| + * | | + * | String area. | + * | | + * |---------------| <-- Top of stack. + * : : + * : : + * \---------------/ 0xffffffff + */ +static int +set_exe(struct psi_process *proci, struct kinfo_proc *p) +{ + int mib[3], argmax, nargs; + size_t size; + char *procargs, *cp; + int i; + int env_start = 0; + + /* Get the maximum process arguments size. */ + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + size = sizeof(argmax); + + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, "sysctl() argmax"); + return -1; + } + + /* Allocate space for the arguments. */ + procargs = (char *)psi_malloc(argmax); + if (procargs == NULL) + return -1; + + /* Make a sysctl() call to get the raw argument space of the process. */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = p->kp_proc.p_pid; + + size = (size_t)argmax; + + if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) { + /* We failed to get the exe info, but it's not fatal. We probably just + * didn't have permission to access the KERN_PROCARGS2 for this + * process. */ + psi_free(procargs); + proci->exe_status = PSI_STATUS_PRIVS; + proci->argc_status = PSI_STATUS_PRIVS; + proci->argv_status = PSI_STATUS_PRIVS; + proci->envc_status = PSI_STATUS_PRIVS; + proci->envv_status = PSI_STATUS_PRIVS; + proci->command_status = PSI_STATUS_PRIVS; + return 0; + } + + memcpy(&nargs, procargs, sizeof(nargs)); + cp = procargs + sizeof(nargs); + + /* Save the exe */ + proci->exe = psi_strdup(cp); + if (proci->exe == NULL) { + psi_free(procargs); + return -1; + } + proci->exe_status = PSI_STATUS_OK; + + /* Skip over the exe. */ + cp += strlen(cp); + if (cp == &procargs[size]) { + psi_free(procargs); + PyErr_SetString(PyExc_OSError, "Did not find args and env"); + return -1; + } + + /* Skip trailing '\0' characters. */ + for (; cp < &procargs[size]; cp++) { + if (*cp != '\0') { + /* Beginning of first argument reached. */ + break; + } + } + if (cp == &procargs[size]) { + psi_free(procargs); + /* We dont' have any arguments or environment */ + if (nargs == 0) { + proci->argc = 0; + proci->argc_status = PSI_STATUS_OK; + proci->argv = NULL; + proci->argv_status = PSI_STATUS_OK; + proci->envc = 0; + proci->envc_status = PSI_STATUS_OK; + proci->envv = NULL; + proci->envv_status = PSI_STATUS_OK; + /* Update proci->command */ + if (command_from_argv(&proci->command, proci->argv, proci->argc) < 0) { + psi_free(procargs); + return -1; + } + proci->command_status = PSI_STATUS_OK; + return 0; + } else { + PyErr_SetString(PyExc_OSError, "Did not find args and env"); + return -1; + } + } + + /* The argument list */ + proci->argc = nargs; + proci->argc_status = PSI_STATUS_OK; + proci->argv = psi_strings_to_array(cp, nargs); + if (proci->argv == NULL) { + psi_free(procargs); + return -1; + } + proci->argv_status = PSI_STATUS_OK; + if (command_from_argv(&proci->command, proci->argv, proci->argc) < 0) { + psi_free(procargs); + return -1; + } + proci->command_status = PSI_STATUS_OK; + + /* The environment */ + for (i = 0; i < nargs; i++) { + env_start += strlen(proci->argv[i])+1; + } + env_start--; + proci->envc = 0; + for (i = 0; ; i++) { + if (*(cp+env_start + i) == '\0') { + if (*(cp+env_start + i + 1) == '\0') + break; + else + proci->envc++; + } + } + proci->envc_status = PSI_STATUS_OK; + proci->envv = psi_strings_to_array(cp+env_start+1, proci->envc); + psi_free(procargs); + if (proci->envv == NULL) + return -1; + proci->envv_status = PSI_STATUS_OK; + + return 0; +} + + +static int +command_from_argv(char **command, char **argv, int argc){ + int i; + int command_len = 0; + int offset=0; + + for (i=0; i<argc; i++) + command_len += strlen(argv[i]) + 1; + *command = psi_malloc(command_len); + if (*command == NULL) { + return -1; + } + for (i=0; i<argc; i++) { + strcpy(*command+offset, argv[i]); + *(*command + offset + strlen(argv[i])) = ' '; + offset = offset + strlen(argv[i]) + 1; + } + *(*command + offset - 1) = '\0'; + + return 0; +} + + +static int +set_cwd(struct psi_process *proci, struct kinfo_proc *p) +{ + /* + * Current working directory of a process is not available on the mac... + * Ref http://bitbucket.org/chrismiles/psi/issue/4/implement-processcwd-for-darwin + */ + proci->cwd_status = PSI_STATUS_NA; + return 0; +} + + +static int +set_kp_proc(struct psi_process *proci, struct kinfo_proc *p) +{ + proci->name = psi_strdup(p->kp_proc.p_comm); + if (proci->name == NULL) + return -1; + proci->name_status = PSI_STATUS_OK; + + proci->nice = p->kp_proc.p_nice; + proci->nice_status = PSI_STATUS_OK; + + proci->priority = p->kp_proc.p_priority; + proci->priority_status = PSI_STATUS_OK; + + proci->status = p->kp_proc.p_stat; + proci->status_status = PSI_STATUS_OK; + + proci->start_time.tv_sec = p->kp_proc.p_starttime.tv_sec; + proci->start_time.tv_nsec = p->kp_proc.p_starttime.tv_usec * 1000; + proci->start_time_status = PSI_STATUS_OK; + + return 0; +} + + +static int +set_kp_eproc(struct psi_process *proci, struct kinfo_proc *p) +{ + dev_t tdev; + char *ttname; + + proci->egid = p->kp_eproc.e_pcred.p_svgid; + proci->egid_status = PSI_STATUS_OK; + + proci->euid = p->kp_eproc.e_pcred.p_svuid; + proci->euid_status = PSI_STATUS_OK; + + proci->pgrp = p->kp_eproc.e_pgid; + proci->pgrp_status = PSI_STATUS_OK; + + proci->ppid = p->kp_eproc.e_ppid; + proci->ppid_status = PSI_STATUS_OK; + + proci->rgid = p->kp_eproc.e_pcred.p_rgid; + proci->rgid_status = PSI_STATUS_OK; + + proci->ruid = p->kp_eproc.e_pcred.p_ruid; + proci->ruid_status = PSI_STATUS_OK; + + proci->sid = (int)p->kp_eproc.e_sess; + proci->sid_status = PSI_STATUS_OK; + + tdev = p->kp_eproc.e_tdev; + if (tdev != NODEV && (ttname = devname(tdev, S_IFCHR)) != NULL) { + /* Prepend with "/dev/" for compatibility with other architectures */ + char terminaldev[64] = "/dev/"; + strncat(terminaldev, ttname, 64); + + proci->terminal = psi_strdup(terminaldev); + proci->terminal_status = PSI_STATUS_OK; + } else { + proci->terminal = psi_strdup(""); + proci->terminal_status = PSI_STATUS_OK; + } + + return 0; +} + + +static int +set_task(struct psi_process *proci, struct kinfo_proc *p) +{ + task_port_t task; + unsigned int info_count; + struct task_basic_info tasks_info; + thread_array_t thread_list; + unsigned int thread_count; + + + if (task_for_pid(mach_task_self(), + p->kp_proc.p_pid, &task) != KERN_SUCCESS) { + proci->pcpu_status = PSI_STATUS_PRIVS; + proci->utime_status = PSI_STATUS_PRIVS; + proci->stime_status = PSI_STATUS_PRIVS; + proci->nthreads_status = PSI_STATUS_PRIVS; + proci->rss_status = PSI_STATUS_PRIVS; + proci->vsz_status = PSI_STATUS_PRIVS; + return 0; + } + + if (task_threads(task, &thread_list, &thread_count) == KERN_SUCCESS) { + int i; + struct timespec utime = { 0, 0 }; + struct timespec stime = { 0, 0 }; + int t_cpu = 0; + int failed = 0; + + proci->nthreads = thread_count; + proci->nthreads_status = PSI_STATUS_OK; + + for (i = 0; i < thread_count; ++i) { + struct thread_basic_info t_info; + unsigned int icount = THREAD_BASIC_INFO_COUNT; + + if (thread_info(thread_list[i], THREAD_BASIC_INFO, + (thread_info_t)&t_info, &icount) == KERN_SUCCESS) { + utime.tv_sec += t_info.user_time.seconds; + utime.tv_nsec += t_info.user_time.microseconds * 1000; + stime.tv_sec += t_info.system_time.seconds; + stime.tv_nsec += t_info.system_time.microseconds * 1000; + t_cpu += t_info.cpu_usage; + } else { + failed = 1; + } + } + + if (failed) { + proci->pcpu_status = PSI_STATUS_PRIVS; + proci->utime_status = PSI_STATUS_PRIVS; + proci->stime_status = PSI_STATUS_PRIVS; + } else { + proci->pcpu = 100.0 * (double)(t_cpu) / TH_USAGE_SCALE; + proci->pcpu_status = PSI_STATUS_OK; + + proci->utime = utime; + proci->utime_status = PSI_STATUS_OK; + + proci->stime = stime; + proci->stime_status = PSI_STATUS_OK; + } + } else { + proci->pcpu_status = PSI_STATUS_PRIVS; + proci->utime_status = PSI_STATUS_PRIVS; + proci->stime_status = PSI_STATUS_PRIVS; + proci->nthreads_status = PSI_STATUS_PRIVS; + } + vm_deallocate(mach_task_self(), + (vm_address_t)thread_list, sizeof(thread_array_t)*(thread_count)); + + info_count = TASK_BASIC_INFO_COUNT; + if (task_info(task, TASK_BASIC_INFO, + (task_info_t)&tasks_info, &info_count) == KERN_SUCCESS) { + vm_region_basic_info_data_64_t b_info; + vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; + vm_size_t size; + mach_port_t object_name; + + /* + * try to determine if this task has the split libraries mapped in... if + * so, adjust its virtual size down by the 2 segments that are used for + * split libraries + */ + info_count = VM_REGION_BASIC_INFO_COUNT_64; + if (vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&b_info, &info_count, + &object_name) == KERN_SUCCESS) { + if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && + tasks_info.virtual_size > + (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) { + tasks_info.virtual_size -= + (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); + } + } + + proci->rss = tasks_info.resident_size; + proci->rss_status = PSI_STATUS_OK; + proci->vsz = tasks_info.virtual_size; + proci->vsz_status = PSI_STATUS_OK; + } else { + proci->rss_status = PSI_STATUS_PRIVS; + proci->vsz_status = PSI_STATUS_PRIVS; + } + + return 0; +} + +/** Calculate the cputime from utime and stime + * + * This really just adds two struct timespec values together. + */ +static struct timespec +calc_cputime(const struct timespec utime, const struct timespec stime) +{ + struct timespec cputime; + + cputime.tv_sec = utime.tv_sec + stime.tv_sec; + cputime.tv_nsec = (utime.tv_nsec + stime.tv_nsec) % 1000000000; + cputime.tv_sec += (utime.tv_nsec + stime.tv_nsec) / 1000000000; + return cputime; +} +
