r11579: syncing up perf counter code cfrom trunk
authorGerald Carter <jerry@samba.org>
Tue, 8 Nov 2005 16:33:45 +0000 (16:33 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:05:21 +0000 (11:05 -0500)
14 files changed:
examples/perfcounter/Makefile [new file with mode: 0644]
examples/perfcounter/perf.h [new file with mode: 0644]
examples/perfcounter/perf_writer.c [new file with mode: 0644]
examples/perfcounter/perf_writer_cpu.c [new file with mode: 0644]
examples/perfcounter/perf_writer_disk.c [new file with mode: 0644]
examples/perfcounter/perf_writer_mem.c [new file with mode: 0644]
examples/perfcounter/perf_writer_process.c [new file with mode: 0644]
examples/perfcounter/perf_writer_util.c [new file with mode: 0644]
examples/perfcounter/perfcountd.init [new file with mode: 0755]
source/param/loadparm.c
source/registry/reg_frontend.c
source/registry/reg_perfcount.c
source/services/services_db.c
source/utils/net_rpc_registry.c

diff --git a/examples/perfcounter/Makefile b/examples/perfcounter/Makefile
new file mode 100644 (file)
index 0000000..07bc765
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# Copyright (C) Marcin Krzysztof Porwit    2005
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# 
+
+SAMBA_SRC_DIR=../../source
+TDB_SRC_DIR=$(SAMBA_SRC_DIR)/tdb
+
+CFLAGS = -g -I$(SAMBA_SRC_DIR)/include -I$(TDB_SRC_DIR)
+CC = gcc
+
+PROGS = perfcount
+TDB_OBJ = $(TDB_SRC_DIR)/tdb.o $(TDB_SRC_DIR)/spinlock.o $(TDB_SRC_DIR)/tdbback.o
+PERF_WRITER_OBJ = perf_writer.o perf_writer_mem.o perf_writer_util.o perf_writer_cpu.o perf_writer_process.o perf_writer_disk.o
+
+default: $(PROGS)
+
+$(TDB_OBJ):
+       cd $(TDB_SRC_DIR) && make
+
+perfcount: $(PERF_WRITER_OBJ) $(TDB_OBJ)
+       $(CC) $(CFLAGS) -o perfcount $(PERF_WRITER_OBJ) $(TDB_OBJ)
+
+clean:
+       rm -f $(PROGS) *.o *~ *% core
diff --git a/examples/perfcounter/perf.h b/examples/perfcounter/perf.h
new file mode 100644 (file)
index 0000000..7279e78
--- /dev/null
@@ -0,0 +1,196 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PERF_H__
+#define __PERF_H__
+
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include "tdb.h"
+#include <rpc_perfcount_defs.h>
+#include <sys/statfs.h>
+#include <sys/times.h>
+#include <sys/sysinfo.h>
+
+#define NUM_COUNTERS 10
+
+#define NAME_LEN 256
+#define HELP_LEN 1024
+
+#define PERF_OBJECT 0
+#define PERF_INSTANCE 1
+#define PERF_COUNTER 2
+
+#define FALSE 0
+#define TRUE !FALSE
+
+#define PROC_BUF 256
+#define LARGE_BUF 16384
+
+typedef struct perf_counter
+{
+    int index;
+    char name[NAME_LEN];
+    char help[HELP_LEN];
+    char relationships[NAME_LEN];
+    unsigned int counter_type;
+    int record_type;
+} PerfCounter;
+
+typedef struct mem_data
+{
+    unsigned int availPhysKb;
+    unsigned int availSwapKb;
+    unsigned int totalPhysKb;
+    unsigned int totalSwapKb;
+} MemData;
+
+typedef struct mem_info
+{
+    PerfCounter memObjDesc;
+    PerfCounter availPhysKb;
+    PerfCounter availSwapKb;
+    PerfCounter totalPhysKb;
+    PerfCounter totalSwapKb;
+    MemData *data;
+} MemInfo;
+
+typedef struct cpu_data
+{
+    unsigned long long user;
+    unsigned long long nice;
+    unsigned long long system;
+    unsigned long long idle;
+} CPUData;
+
+typedef struct cpu_info
+{
+    unsigned int numCPUs;
+    PerfCounter cpuObjDesc;
+    PerfCounter userCPU;
+    PerfCounter niceCPU;
+    PerfCounter systemCPU;
+    PerfCounter idleCPU;
+    CPUData *data;
+} CPUInfo;
+
+typedef struct disk_meta_data
+{
+       char name[NAME_LEN];
+       char mountpoint[NAME_LEN];
+} DiskMetaData;
+
+typedef struct disk_data
+{
+       unsigned long long freeMegs;
+       unsigned int writesPerSec;
+       unsigned int readsPerSec;
+} DiskData;
+
+typedef struct disk_info
+{
+       unsigned int numDisks;
+       DiskMetaData *mdata;
+       PerfCounter diskObjDesc;
+       PerfCounter freeMegs;
+       PerfCounter writesPerSec;
+       PerfCounter readsPerSec;
+       DiskData *data;
+} DiskInfo;
+
+typedef struct process_data
+{
+       unsigned int runningProcessCount;
+} ProcessData;
+
+typedef struct process_info
+{
+       PerfCounter processObjDesc;
+       PerfCounter runningProcessCount;
+       ProcessData *data;
+} ProcessInfo;
+
+typedef struct perf_data_block
+{
+       unsigned int counter_id;
+       unsigned int num_counters;
+       unsigned int NumObjectTypes;
+       unsigned long long PerfTime;
+       unsigned long long PerfFreq;
+       unsigned long long PerfTime100nSec;
+       MemInfo memInfo;
+       CPUInfo cpuInfo;
+       ProcessInfo processInfo;
+       DiskInfo diskInfo;
+} PERF_DATA_BLOCK;
+
+typedef struct runtime_settings
+{
+    /* Runtime flags */
+    int dflag;
+    /* DB path names */
+    char dbDir[PATH_MAX];
+    char nameFile[PATH_MAX];
+    char counterFile[PATH_MAX];
+    /* TDB context */
+    TDB_CONTEXT *cnames;
+    TDB_CONTEXT *cdata;
+} RuntimeSettings;
+
+/* perf_writer_ng_util.c function prototypes */
+void fatal(char *msg);
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags);
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *datastring, size_t datasize, int flags);
+void make_key(char *buf, int buflen, int key_part1, char *key_part2);
+void parse_flags(RuntimeSettings *rt, int argc, char **argv);
+void setup_file_paths(RuntimeSettings *rt);
+void daemonize(RuntimeSettings *rt);
+
+/* perf_writer_ng_mem.c function prototypes */
+void get_meminfo(PERF_DATA_BLOCK *data);
+void init_memdata_desc(PERF_DATA_BLOCK *data);
+void init_memdata(PERF_DATA_BLOCK *data);
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+void init_perf_counter(PerfCounter *counter, PerfCounter *parent, unsigned int index, char *name, char *help, int counter_type, int record_type);
+
+/* perf_writer_ng_cpu.c function prototypes */
+unsigned long long get_cpufreq();
+void init_cpudata_desc(PERF_DATA_BLOCK *data);
+void get_cpuinfo(PERF_DATA_BLOCK *data);
+void init_cpu_data(PERF_DATA_BLOCK *data);
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+
+#endif /* __PERF_H__ */
diff --git a/examples/perfcounter/perf_writer.c b/examples/perfcounter/perf_writer.c
new file mode 100644 (file)
index 0000000..04127f5
--- /dev/null
@@ -0,0 +1,214 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+sig_atomic_t keep_running = TRUE;
+
+/* allocates memory and gets numCPUs, total memory, and PerfFreq, number of disks... */
+void get_constants(PERF_DATA_BLOCK *data)
+{
+    data->cpuInfo.numCPUs = sysconf(_SC_NPROCESSORS_ONLN);
+    data->PerfFreq = sysconf(_SC_CLK_TCK);
+    init_mem_data(data);
+    init_cpu_data(data);
+    init_process_data(data);
+    init_disk_data(data);
+
+    return;
+}
+
+void output_num_instances(PerfCounter obj, int numInst, RuntimeSettings rt)
+{
+    char key[NAME_LEN];
+    char sdata[NAME_LEN];
+
+    make_key(key, NAME_LEN, obj.index, "inst");
+    memset(sdata, 0, NAME_LEN);
+    sprintf(sdata, "%d", numInst);
+    add_key(rt.cnames, key, sdata, TDB_INSERT);
+
+    return;
+}
+
+void output_perf_desc(PerfCounter counter, RuntimeSettings rt)
+{
+    char key[NAME_LEN];
+    char sdata[NAME_LEN];
+
+    /* First insert the counter name */
+    make_key(key, NAME_LEN, counter.index, NULL);
+    add_key(rt.cnames, key, counter.name, TDB_INSERT);
+    /* Add the help string */
+    make_key(key, NAME_LEN, counter.index + 1, NULL);
+    add_key(rt.cnames, key, counter.help, TDB_INSERT);
+    /* Add the relationships */
+    make_key(key, NAME_LEN, counter.index, "rel");
+    add_key(rt.cnames, key, counter.relationships, TDB_INSERT);
+    /* Add type data if not PERF_OBJECT or PERF_INSTANCE */
+    if(counter.record_type == PERF_COUNTER)
+    {
+       make_key(key, NAME_LEN, counter.index, "type");
+       memset(sdata, 0, NAME_LEN);
+       sprintf(sdata, "%d", counter.counter_type);
+       add_key(rt.cnames, key, sdata, TDB_INSERT);
+    }
+
+    return;
+}
+
+void initialize(PERF_DATA_BLOCK *data, RuntimeSettings *rt, int argc, char **argv)
+{
+    memset(data, 0, sizeof(*data));
+    memset(rt, 0, sizeof(*data));
+
+    parse_flags(rt, argc, argv);
+    setup_file_paths(rt);
+
+    get_constants(data);
+
+    if(rt->dflag == TRUE)
+       daemonize(rt);
+
+    output_mem_desc(data, *rt);
+    output_cpu_desc(data, *rt);
+    output_process_desc(data, *rt);
+    output_disk_desc(data, *rt);
+
+    return;
+}
+
+void refresh_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+    data->PerfTime100nSec = 0;
+    get_meminfo(data);
+    get_cpuinfo(data);
+    get_processinfo(data);
+    get_diskinfo(data);
+    return;
+}
+
+void output_perf_counter(PerfCounter counter, unsigned long long data,
+                        RuntimeSettings rt, int tdb_flags)
+{
+    char key[NAME_LEN];
+    char sdata[NAME_LEN];
+    unsigned int size_mask;
+
+    make_key(key, NAME_LEN, counter.index, NULL);
+    memset(sdata, 0, NAME_LEN);
+
+    size_mask = counter.counter_type & PERF_SIZE_VARIABLE_LEN;
+
+    if(size_mask == PERF_SIZE_DWORD)
+       sprintf(sdata, "%d", (unsigned int)data);
+    else if(size_mask == PERF_SIZE_LARGE)
+       sprintf(sdata, "%Lu", data);
+
+    add_key(rt.cdata, key, sdata, tdb_flags);
+
+    return;
+}
+
+void output_perf_instance(int parentObjInd,
+                         int instanceInd,
+                         void *instData,
+                         size_t dsize,
+                         char *name,
+                         RuntimeSettings rt,
+                         int tdb_flags)
+{
+    char key[NAME_LEN];
+    char sdata[NAME_LEN];
+
+    memset(key, 0, NAME_LEN);
+    sprintf(key, "%di%d", parentObjInd, instanceInd);
+    add_key_raw(rt.cdata, key, instData, dsize, tdb_flags);
+
+    /* encode name */
+    memset(key, 0, NAME_LEN);
+    sprintf(key, "%di%dname", parentObjInd, instanceInd);
+    add_key(rt.cnames, key, name, tdb_flags);
+
+    return;
+}
+
+void output_global_data(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+    int i;
+    char key[NAME_LEN];
+    char sdata[NAME_LEN];
+    
+     /* Initialize BaseIndex */
+    make_key(key, NAME_LEN, 1, NULL);
+    memset(sdata, 0, NAME_LEN);
+    sprintf(sdata, "%d", data->num_counters);
+    add_key(rt.cnames, key, sdata, tdb_flags);
+    /* Initialize PerfTime, PerfFreq and PerfTime100nSec */
+    memset(sdata, 0, NAME_LEN);
+    make_key(key, NAME_LEN, 0, "PerfTime");
+    sprintf(sdata, "%Lu", data->PerfTime);
+    add_key(rt.cdata, key, sdata, tdb_flags);
+    make_key(key, NAME_LEN, 0, "PerfTime100nSec");
+    memset(sdata, 0, NAME_LEN);
+    sprintf(sdata, "%Lu", data->PerfTime100nSec);
+    add_key(rt.cdata, key, sdata, tdb_flags);
+    memset(sdata, 0, NAME_LEN);
+    make_key(key, NAME_LEN, 0, "PerfFreq");
+    sprintf(sdata, "%Lu", data->PerfFreq);
+    add_key(rt.cnames, key, sdata, tdb_flags);
+
+    return;
+}
+
+void output_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+    output_global_data(data, rt, tdb_flags);
+    output_meminfo(data, rt, tdb_flags);
+    output_cpuinfo(data, rt, tdb_flags);
+    output_processinfo(data, rt, tdb_flags);
+    output_diskinfo(data, rt, tdb_flags);
+    return;
+}
+
+void update_counters(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+    refresh_perf_data_block(data, rt);
+    output_perf_data_block(data, rt, TDB_REPLACE);
+
+    return;
+}
+
+int main(int argc, char **argv)
+{
+    PERF_DATA_BLOCK data;
+    RuntimeSettings rt;
+
+    initialize(&data, &rt, argc, argv);
+
+    while(keep_running)
+    {
+       update_counters(&data, rt);
+       sleep(1);
+    }
+    
+    return 0;
+}
diff --git a/examples/perfcounter/perf_writer_cpu.c b/examples/perfcounter/perf_writer_cpu.c
new file mode 100644 (file)
index 0000000..7786c94
--- /dev/null
@@ -0,0 +1,190 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+void init_cpudata_desc(PERF_DATA_BLOCK *data)
+{
+    init_perf_counter(&(data->cpuInfo.cpuObjDesc),
+                     &(data->cpuInfo.cpuObjDesc),
+                     get_counter_id(data),
+                     "Processor",
+                     "The Processor object consists of counters that describe the behavior of the CPU.",
+                     0,
+                     PERF_OBJECT);
+    init_perf_counter(&(data->cpuInfo.userCPU),
+                     &(data->cpuInfo.cpuObjDesc),
+                     get_counter_id(data),
+                     "\% User CPU Utilization",
+                     "\% User CPU Utilization is the percentage of the CPU used by  processes executing user code.",
+                     PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->cpuInfo.systemCPU),
+                     &(data->cpuInfo.cpuObjDesc),
+                     get_counter_id(data),
+                     "\% System CPU Utilization",
+                     "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.",
+                     PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->cpuInfo.niceCPU),
+                     &(data->cpuInfo.cpuObjDesc),
+                     get_counter_id(data),
+                     "\% Nice CPU Utilization",
+                     "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.",
+                     PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->cpuInfo.idleCPU),
+                     &(data->cpuInfo.cpuObjDesc),
+                     get_counter_id(data),
+                     "\% Idle CPU",
+                     "\% Idle CPU is the percentage of the CPU not doing any work.",
+                     PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+                     PERF_COUNTER);
+
+    return;
+}
+
+void get_cpuinfo(PERF_DATA_BLOCK *data)
+{
+    int num, i;
+    unsigned int cpuid;
+    char buf[PROC_BUF];
+    static FILE *fp = NULL;
+
+    if(!fp)
+    {
+       if(!(fp = fopen("/proc/stat", "r")))
+       {
+           perror("get_cpuinfo: fopen");
+           exit(1);
+       }
+    }
+
+    rewind(fp);
+    fflush(fp);
+
+    /* Read in the first line and discard it -- that has the CPU summary */
+    if(!fgets(buf, sizeof(buf), fp))
+    {
+       perror("get_cpuinfo: fgets");
+       exit(1);
+    }
+    for(i = 0; i < data->cpuInfo.numCPUs; i++)
+    {
+       if(!fgets(buf, sizeof(buf), fp))
+       {
+           perror("get_cpuinfo: fgets");
+           exit(1);
+       }
+       num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu",
+                    &cpuid,
+                    &data->cpuInfo.data[i].user,
+                    &data->cpuInfo.data[i].nice,
+                    &data->cpuInfo.data[i].system,
+                    &data->cpuInfo.data[i].idle);
+       if(i != cpuid)
+       {
+           perror("get_cpuinfo: /proc/stat inconsistent?");
+           exit(1);
+       }
+       /*
+         Alternate way of doing things:
+         struct tms buffer;
+         data->PerfTime100nSec = times(&buffer);
+       */
+       data->PerfTime100nSec += data->cpuInfo.data[i].user +
+           data->cpuInfo.data[i].nice +
+           data->cpuInfo.data[i].system +
+           data->cpuInfo.data[i].idle;
+    }
+    data->PerfTime100nSec /= data->cpuInfo.numCPUs;
+    return;
+}
+
+void init_cpu_data(PERF_DATA_BLOCK *data)
+{
+    data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data));
+    if(!data->cpuInfo.data)
+    {
+       perror("init_cpu_data: out of memory");
+       exit(1);
+    }
+
+    init_cpudata_desc(data);
+
+    get_cpuinfo(data);
+
+    return;
+}   
+
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+    output_perf_desc(data->cpuInfo.cpuObjDesc, rt);
+    output_perf_desc(data->cpuInfo.userCPU, rt);
+    output_perf_desc(data->cpuInfo.niceCPU, rt);
+    output_perf_desc(data->cpuInfo.systemCPU, rt);
+    output_perf_desc(data->cpuInfo.idleCPU, rt);
+    if(data->cpuInfo.numCPUs > 1)
+           output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt);
+
+    return;
+}
+
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+    int i;
+    char buf[NAME_LEN];
+
+    output_perf_counter(data->cpuInfo.userCPU,
+                       data->cpuInfo.data[0].user,
+                       rt, tdb_flags);
+    output_perf_counter(data->cpuInfo.systemCPU,
+                       data->cpuInfo.data[0].system,
+                       rt, tdb_flags);
+    output_perf_counter(data->cpuInfo.niceCPU,
+                       data->cpuInfo.data[0].nice,
+                       rt, tdb_flags);
+    output_perf_counter(data->cpuInfo.idleCPU,
+                       data->cpuInfo.data[0].idle,
+                       rt, tdb_flags);
+    if(data->cpuInfo.numCPUs > 1)
+      {
+             for(i = 0; i < data->cpuInfo.numCPUs; i++)
+             {
+                     memset(buf, 0, NAME_LEN);
+                     sprintf(buf, "cpu%d", i);
+                     output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+                                          i,
+                                          (void *)&(data->cpuInfo.data[i]),
+                                          sizeof(data->cpuInfo.data[i]),
+                                          buf, rt, tdb_flags);
+             }
+             
+             memset(buf, 0, NAME_LEN);
+             sprintf(buf, "_Total");
+             output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+                                  i,
+                                  (void *)&(data->cpuInfo.data[i]),
+                                  sizeof(data->cpuInfo.data[i]),
+                                  buf, rt, tdb_flags);
+      }
+    return;
+}
diff --git a/examples/perfcounter/perf_writer_disk.c b/examples/perfcounter/perf_writer_disk.c
new file mode 100644 (file)
index 0000000..b2b4c96
--- /dev/null
@@ -0,0 +1,225 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+void init_diskdata_desc(PERF_DATA_BLOCK *data)
+{
+       init_perf_counter(&(data->diskInfo.diskObjDesc),
+                         &(data->diskInfo.diskObjDesc),
+                         get_counter_id(data),
+                         "Logical Disk",
+                         "The Logical Disk object consists of counters that show information about disks.",
+                         0,
+                         PERF_OBJECT);
+       init_perf_counter(&(data->diskInfo.freeMegs),
+                         &(data->diskInfo.diskObjDesc),
+                         get_counter_id(data),
+                         "Megabytes Free",
+                         "The amount of available disk space, in megabytes.",
+                         PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+                         PERF_COUNTER);
+       init_perf_counter(&(data->diskInfo.writesPerSec),
+                         &(data->diskInfo.diskObjDesc),
+                         get_counter_id(data),
+                         "Writes/sec",
+                         "The number of writes per second to that disk.",
+                         PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+                         PERF_COUNTER);
+       init_perf_counter(&(data->diskInfo.readsPerSec),
+                         &(data->diskInfo.diskObjDesc),
+                         get_counter_id(data),
+                         "Reads/sec",
+                         "The number of reads of that disk per second.",
+                         PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+                         PERF_COUNTER);
+
+       return;
+}
+void init_num_disks(PERF_DATA_BLOCK *data)
+{
+       FILE *mtab;
+       char buf[PROC_BUF];
+       char *start, *stop;
+       int i = 0, num;
+
+       if(!(mtab = fopen("/etc/mtab", "r")))
+       {
+               perror("init_disk_names: fopen");
+               exit(1);
+       }
+
+       rewind(mtab);
+       fflush(mtab);
+
+       while(fgets(buf, sizeof(buf), mtab))
+       {
+               if(start = strstr(buf, "/dev/"))
+               {
+                       if(start = strstr(start, "da"))
+                       {
+                               i++;
+                       }
+               }
+       }
+
+       data->diskInfo.numDisks = i;
+       fclose(mtab);
+
+       return;
+}
+       
+void init_disk_names(PERF_DATA_BLOCK *data)
+{
+       FILE *mtab;
+       char buf[PROC_BUF];
+       char *start, *stop;
+       int i = 0, num;
+
+       if(!(mtab = fopen("/etc/mtab", "r")))
+       {
+               perror("init_disk_names: fopen");
+               exit(1);
+       }
+
+       rewind(mtab);
+       fflush(mtab);
+
+       while(fgets(buf, sizeof(buf), mtab))
+       {
+               if(start = strstr(buf, "/dev/"))
+               {
+                       if(start = strstr(start, "da"))
+                       {
+                               start -=1;
+                               stop = strstr(start, " ");
+                               memcpy(data->diskInfo.mdata[i].name, start, stop - start);
+                               start = stop +1;
+                               stop = strstr(start, " ");
+                               memcpy(data->diskInfo.mdata[i].mountpoint, start, stop - start);
+                               i++;
+                       }
+               }
+       }
+
+       fclose(mtab);
+
+       return;
+}
+
+void get_diskinfo(PERF_DATA_BLOCK *data)
+{
+       int i;
+       DiskData *p;
+       struct statfs statfsbuf;
+       int status, num;
+       char buf[LARGE_BUF], *start;
+       FILE *diskstats;
+       long reads, writes, discard;
+
+       diskstats = fopen("/proc/diskstats", "r");
+       rewind(diskstats);
+       fflush(diskstats);
+       status = fread(buf, sizeof(char), LARGE_BUF, diskstats);
+       fclose(diskstats);
+
+       for(i = 0; i < data->diskInfo.numDisks; i++)
+       {
+               p = &(data->diskInfo.data[i]);
+               status = statfs(data->diskInfo.mdata[i].mountpoint, &statfsbuf);
+               p->freeMegs = (statfsbuf.f_bfree*statfsbuf.f_bsize)/1048576;
+               start = strstr(buf, data->diskInfo.mdata[i].name);
+               start += strlen(data->diskInfo.mdata[i].name) + 1;
+               num = sscanf(start, "%u %u %u %u",
+                            &reads,
+                            &discard, 
+                            &writes, 
+                            &discard);
+               p->writesPerSec = writes;
+               p->readsPerSec = reads;
+               fprintf(stderr, "%s:\t%u\t%u\n",
+                       data->diskInfo.mdata[i].mountpoint,
+                       reads, writes);
+       }
+       return;
+}
+void init_disk_data(PERF_DATA_BLOCK *data)
+{
+       init_diskdata_desc(data);
+       
+       init_num_disks(data);
+
+       data->diskInfo.mdata = calloc(data->diskInfo.numDisks, sizeof(DiskMetaData));
+       if(!data->diskInfo.mdata)
+       {
+               fatal("init_disk_data: out of memory");
+       }
+
+       init_disk_names(data);
+
+       data->diskInfo.data = calloc(data->diskInfo.numDisks, sizeof(DiskData));
+       if(!data->diskInfo.data)
+       {
+               fatal("init_disk_data: out of memory");
+       }
+
+       get_diskinfo(data);
+
+       return;
+}
+
+void output_disk_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+       output_perf_desc(data->diskInfo.diskObjDesc, rt);
+       output_perf_desc(data->diskInfo.freeMegs, rt);
+       output_perf_desc(data->diskInfo.writesPerSec, rt);
+       output_perf_desc(data->diskInfo.readsPerSec, rt);
+       output_num_instances(data->diskInfo.diskObjDesc, data->diskInfo.numDisks, rt);
+
+       return;
+}
+
+void output_diskinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+       int i;
+       
+       output_perf_counter(data->diskInfo.freeMegs,
+                           data->diskInfo.data[0].freeMegs,
+                           rt, tdb_flags);
+       output_perf_counter(data->diskInfo.writesPerSec,
+                           (unsigned long long)data->diskInfo.data[0].writesPerSec,
+                           rt, tdb_flags);
+       output_perf_counter(data->diskInfo.readsPerSec,
+                           (unsigned long long)data->diskInfo.data[0].readsPerSec,
+                           rt, tdb_flags);
+
+       for(i = 0; i < data->diskInfo.numDisks; i++)
+       {
+               output_perf_instance(data->diskInfo.diskObjDesc.index,
+                                    i,
+                                    (void *)&(data->diskInfo.data[i]),
+                                    sizeof(DiskData),
+                                    data->diskInfo.mdata[i].mountpoint,
+                                    rt, tdb_flags);
+       }
+
+       return;
+}
diff --git a/examples/perfcounter/perf_writer_mem.c b/examples/perfcounter/perf_writer_mem.c
new file mode 100644 (file)
index 0000000..1a9a3ca
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+void get_meminfo(PERF_DATA_BLOCK *data)
+{
+    int status;
+    struct sysinfo info;
+    status = sysinfo(&info);
+    
+    data->memInfo.data->availPhysKb = (info.freeram * info.mem_unit)/1024;
+    data->memInfo.data->availSwapKb = (info.freeswap * info.mem_unit)/1024;
+    data->memInfo.data->totalPhysKb = (info.totalram * info.mem_unit)/1024;
+    data->memInfo.data->totalSwapKb = (info.totalswap * info.mem_unit)/1024;
+
+    /* Also get uptime since we have the structure */
+    data->PerfTime = (unsigned long)info.uptime;
+
+    return;
+}
+
+void init_memdata_desc(PERF_DATA_BLOCK *data)
+{
+    init_perf_counter(&(data->memInfo.memObjDesc),
+                     &(data->memInfo.memObjDesc),
+                     get_counter_id(data),
+                     "Memory",
+                     "The Memory performance object consists of counters that describe the behavior of physical and virtual memory on the computer.",
+                     0,
+                     PERF_OBJECT);
+    init_perf_counter(&(data->memInfo.availPhysKb),
+                     &(data->memInfo.memObjDesc),
+                     get_counter_id(data),
+                     "Available Physical Kilobytes",
+                     "Available Physical Kilobytes is the number of free kilobytes in physical memory",
+                     PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->memInfo.availSwapKb),
+                     &(data->memInfo.memObjDesc),
+                     get_counter_id(data),
+                     "Available Swap Kilobytes",
+                     "Available Swap Kilobytes is the number of free kilobytes in swap space",
+                     PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->memInfo.totalPhysKb),
+                     &(data->memInfo.memObjDesc),
+                     get_counter_id(data),
+                     "Total Physical Kilobytes",
+                     "Total Physical Kilobytes is a base counter",
+                     PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+                     PERF_COUNTER);
+    init_perf_counter(&(data->memInfo.totalSwapKb),
+                     &(data->memInfo.memObjDesc),
+                     get_counter_id(data),
+                     "Total Swap Kilobytes",
+                     "Total Swap Kilobytes is a base counter",
+                     PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+                     PERF_COUNTER);
+
+    return;
+}
+
+void init_mem_data(PERF_DATA_BLOCK *data)
+{
+    data->memInfo.data = calloc(1, sizeof(*data->memInfo.data));
+    if(!data->memInfo.data)
+    {
+       perror("init_memdata: out of memory");
+       exit(1);
+    }
+
+    init_memdata_desc(data);
+
+    get_meminfo(data);
+
+    return;
+}
+
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+    output_perf_desc(data->memInfo.memObjDesc, rt);
+    output_perf_desc(data->memInfo.availPhysKb, rt);
+    output_perf_desc(data->memInfo.availSwapKb, rt);
+    output_perf_desc(data->memInfo.totalPhysKb, rt);
+    output_perf_desc(data->memInfo.totalSwapKb, rt);
+
+    return;
+}
+
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+    output_perf_counter(data->memInfo.availPhysKb, 
+                       (unsigned long long)data->memInfo.data->availPhysKb, 
+                       rt, tdb_flags);
+    output_perf_counter(data->memInfo.availSwapKb, 
+                       (unsigned long long)data->memInfo.data->availSwapKb,
+                       rt, tdb_flags);
+    output_perf_counter(data->memInfo.totalPhysKb,
+                       (unsigned long long)data->memInfo.data->totalPhysKb,
+                       rt, tdb_flags);
+    output_perf_counter(data->memInfo.totalSwapKb,
+                       (unsigned long long)data->memInfo.data->totalSwapKb,
+                       rt, tdb_flags);
+
+    return;
+}
diff --git a/examples/perfcounter/perf_writer_process.c b/examples/perfcounter/perf_writer_process.c
new file mode 100644 (file)
index 0000000..75a23da
--- /dev/null
@@ -0,0 +1,86 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+void get_processinfo(PERF_DATA_BLOCK *data)
+{
+  int status;
+  struct sysinfo info;
+  status = sysinfo(&info);
+
+  data->processInfo.data->runningProcessCount = (unsigned int)info.procs;
+
+  return;
+}
+
+void init_processdata_desc(PERF_DATA_BLOCK *data)
+{
+  init_perf_counter(&(data->processInfo.processObjDesc),
+                   &(data->processInfo.processObjDesc),
+                   get_counter_id(data),
+                   "Processes",
+                   "%The Processes performance object displays aggregate information about processes on the machine.",
+                   0,
+                   PERF_OBJECT);
+  init_perf_counter(&(data->processInfo.runningProcessCount),
+                   &(data->processInfo.processObjDesc),
+                   get_counter_id(data),
+                   "Process Count",
+                   "Process Count is the number of processes currently on the machine.",
+                   PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+                   PERF_COUNTER);
+   
+  return;
+}
+
+void init_process_data(PERF_DATA_BLOCK *data)
+{
+  data->processInfo.data = calloc(1, sizeof(*data->processInfo.data));
+  if(!(data->processInfo.data))
+    {
+      perror("init_process_data: out of memory");
+      exit(1);
+    }
+  
+  init_processdata_desc(data);
+
+  get_processinfo(data);
+
+  return;
+}
+
+void output_processinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+       output_perf_counter(data->processInfo.runningProcessCount,
+                           (unsigned long long)data->processInfo.data->runningProcessCount,
+                           rt, tdb_flags);
+
+       return;
+}
+
+void output_process_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+       output_perf_desc(data->processInfo.processObjDesc, rt);
+       output_perf_desc(data->processInfo.runningProcessCount, rt);
+
+       return;
+}
diff --git a/examples/perfcounter/perf_writer_util.c b/examples/perfcounter/perf_writer_util.c
new file mode 100644 (file)
index 0000000..bb6422b
--- /dev/null
@@ -0,0 +1,244 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Performance Counter Daemon
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "perf.h"
+
+extern sig_atomic_t keep_running;
+
+void fatal(char *msg)
+{
+  perror(msg);
+  exit(1);
+}
+
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *databuf, size_t datasize, int flags)
+{
+  TDB_DATA key, data;
+
+  key.dptr = keystring;
+  key.dsize = strlen(keystring);
+  data.dptr = databuf;
+  data.dsize = datasize;
+  fprintf(stderr, "doing insert of [%x] with key [%s] into [%s]\n", 
+         data.dptr, 
+         keystring, 
+         db->name);
+
+  tdb_store(db, key, data, flags);
+}
+
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags)
+{
+  TDB_DATA key, data;
+
+  key.dptr = keystring;
+  key.dsize = strlen(keystring);
+  data.dptr = datastring;
+  data.dsize = strlen(datastring);
+  /*  fprintf(stderr, "doing insert of [%s] with key [%s] into [%s]\n", 
+         data.dptr, 
+         keystring, 
+         db->name);*/
+
+  tdb_store(db, key, data, flags);
+}
+
+void make_key(char *buf, int buflen, int key_part1, char *key_part2)
+{
+    memset(buf, 0, buflen);
+    if(key_part2 != NULL)
+       sprintf(buf, "%d%s", key_part1, key_part2);
+    else
+       sprintf(buf, "%d", key_part1);
+
+    return;
+}
+
+void usage(char *progname)
+{
+    fprintf(stderr, "Usage: %s [-d] [-f <file_path>].\n", progname);
+    fprintf(stderr, "\t-d: run as a daemon.\n");
+    fprintf(stderr, "\t-f <file_path>: path where the TDB files reside.\n");
+    fprintf(stderr, "\t\tDEFAULT is /tmp/counters\n");
+    exit(1);
+}
+
+void parse_flags(RuntimeSettings *rt, int argc, char **argv)
+{
+    int flag;
+    
+    while((flag = getopt(argc, argv, "df:")) != -1)
+    {
+       switch(flag)
+       {
+           case 'd':
+           {
+               rt->dflag = TRUE;
+               break;
+           }
+           case 'f':
+           {
+               memcpy(rt->dbDir, optarg, strlen(optarg));
+               break;
+           }
+           default:
+           {
+               usage(argv[0]);
+           }
+       }
+    }
+
+    return;
+}
+
+void setup_file_paths(RuntimeSettings *rt)
+{
+    int status;
+
+    if(strlen(rt->dbDir) == 0)
+    {
+       /* No file path was passed in, use default */
+       sprintf(rt->dbDir, "/tmp/counters");
+    }
+
+    sprintf(rt->nameFile, "%s/names.tdb", rt->dbDir);
+    sprintf(rt->counterFile, "%s/data.tdb", rt->dbDir);
+
+    mkdir(rt->dbDir, O_RDWR);
+    rt->cnames = tdb_open(rt->nameFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+    rt->cdata = tdb_open(rt->counterFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+
+    if(rt->cnames == NULL || rt->cdata == NULL)
+    {
+       perror("setup_file_paths");
+       exit(1);
+    }
+
+    return;
+}
+
+void sigterm_handler()
+{
+    keep_running = FALSE;
+    return;
+}
+
+void daemonize(RuntimeSettings *rt)
+{
+    pid_t pid;
+    int i;
+    int fd;
+
+    /* Check if we're already a daemon */
+    if(getppid() == 1)
+       return;
+    pid = fork();
+    if(pid < 0)
+       /* can't fork */
+       exit(1);
+    else if(pid > 0)
+    {
+       /* we're the parent */
+       tdb_close(rt->cnames);
+       tdb_close(rt->cdata);
+       exit(0);
+    }
+
+    /* get a new session */
+    if(setsid() == -1)
+       exit(2);
+
+    /* Change CWD */
+    chdir("/");
+
+    /* close file descriptors */
+    close(STDIN_FILENO);
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+
+    /* And reopen them as safe defaults */
+    fd = open("/dev/null", O_RDONLY);
+    if(fd != 0)
+    {
+       dup2(fd, 0);
+       close(fd);
+    }
+    fd = open("/dev/null", O_WRONLY);
+    if(fd != 1)
+    {
+       dup2(fd, 1);
+       close(fd);
+    }
+    fd = open("/dev/null", O_WRONLY);
+    if(fd != 2)
+    {
+       dup2(fd, 2);
+       close(fd);
+    }
+
+    /* handle signals */
+    signal(SIGINT, SIG_IGN);
+    signal(SIGHUP, SIG_IGN);
+    signal(SIGTERM, sigterm_handler);
+
+    return;
+}
+
+int get_counter_id(PERF_DATA_BLOCK *data)
+{
+    data->counter_id += 2;
+    data->num_counters++;
+
+    return data->counter_id;
+}
+
+void init_perf_counter(PerfCounter *counter,
+                      PerfCounter *parent,
+                      unsigned int index,
+                      char *name,
+                      char *help,
+                      int counter_type,
+                      int record_type)
+{
+    counter->index = index;
+    memcpy(counter->name, name, strlen(name));
+    memcpy(counter->help, help, strlen(help));
+    counter->counter_type = counter_type;
+    counter->record_type = record_type;
+
+    switch(record_type)
+    {
+       case PERF_OBJECT:
+           sprintf(counter->relationships, "p");
+           break;
+       case PERF_COUNTER:
+           sprintf(counter->relationships, "c[%d]", parent->index);
+           break;
+       case PERF_INSTANCE:
+           sprintf(counter->relationships, "i[%d]", parent->index);
+           break;
+       default:
+           perror("init_perf_counter: unknown record type");
+           exit(1);
+    }
+
+    return;
+}
diff --git a/examples/perfcounter/perfcountd.init b/examples/perfcounter/perfcountd.init
new file mode 100755 (executable)
index 0000000..bb4148e
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (C) Gerald Carter            2005
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+####################################################################
+
+## This file should have uid root, gid sys and chmod 744
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+killproc() 
+{
+       pid=`ps aux | grep $1 | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+       if [ "$pid" != "" ]; then
+               kill $pid
+       fi
+}
+
+# Start/stop processes 
+
+case "$1" 
+in
+start)
+       /opt/samba/bin/perfcount -d -f /var/lib/samba/perfmon 2> /dev/null
+       if [ $? -ne 0 ]; then
+               echo "Failed!"
+               exit 1
+       fi
+       echo "done!"
+       ;;
+stop)
+       killproc perfcount
+       ;;
+
+status)
+       pid=`ps aux | grep perfcount | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+       if [ "$pid" == "" ]; then
+               echo "Dead!"
+               exit 2;
+       fi
+       echo "OK!"
+       ;;
+restart)
+       $0 stop && $0 start
+       ;;
+
+*)
+       echo "Usage: $0 { start|stop|restart|status }"
+       ;;
+esac
+
+
index d2cbf380daa42cb7ed64548ab68d969f7deaa1b5..d2d739fa726b11dbe2e1f140b3b68da66178c778 100644 (file)
@@ -121,7 +121,6 @@ typedef struct
        char *szConfigFile;
        char *szSMBPasswdFile;
        char *szPrivateDir;
-        char *szCountersDir;
        char **szPassdbBackend;
        char **szPreloadModules;
        char *szPasswordServer;
@@ -848,7 +847,6 @@ static struct parm_struct parm_table[] = {
        {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD}, 
        {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL, NULL, FLAG_ADVANCED}, 
        {"private dir", P_STRING, P_GLOBAL, &Globals.szPrivateDir, NULL, NULL, FLAG_ADVANCED}, 
-       {"counters dir", P_STRING, P_GLOBAL, &Globals.szCountersDir, NULL, NULL, FLAG_ADVANCED},
        {"passdb backend", P_LIST, P_GLOBAL, &Globals.szPassdbBackend, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD}, 
        {"algorithmic rid base", P_INTEGER, P_GLOBAL, &Globals.AlgorithmicRidBase, NULL, NULL, FLAG_ADVANCED}, 
        {"root directory", P_STRING, P_GLOBAL, &Globals.szRootdir, NULL, NULL, FLAG_ADVANCED}, 
@@ -1711,7 +1709,6 @@ FN_GLOBAL_STRING(lp_logfile, &Globals.szLogFile)
 FN_GLOBAL_STRING(lp_configfile, &Globals.szConfigFile)
 FN_GLOBAL_STRING(lp_smb_passwd_file, &Globals.szSMBPasswdFile)
 FN_GLOBAL_STRING(lp_private_dir, &Globals.szPrivateDir)
-FN_GLOBAL_STRING(lp_counters_dir, &Globals.szCountersDir)
 FN_GLOBAL_STRING(lp_serverstring, &Globals.szServerString)
 FN_GLOBAL_INTEGER(lp_printcap_cache_time, &Globals.PrintcapCacheTime)
 FN_GLOBAL_STRING(lp_enumports_cmd, &Globals.szEnumPortsCommand)
index b0e713a8826cfdd6aefcb7c378269d33a4981e76..d5a9d45e8c46ea30a65c2a430f94c4b9ec1602d4 100644 (file)
@@ -131,6 +131,7 @@ BOOL init_registry( void )
 
        svcctl_init_keys();
        eventlog_init_keys();
+       perfcount_init_keys();
 
        /* close and let each smbd open up as necessary */
 
index fe8b355b958f99bd57ae0fb58a354fd93099ccec..a31154fc33b28a2144777291074864b9ab41a61a 100644 (file)
@@ -1,3 +1,25 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Virtual Windows Registry Layer
+ *
+ *  Copyright (C) Marcin Krzysztof Porwit    2005,
+ *  Copyright (C) Gerald (Jerry) Carter      2005.
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
 #include "includes.h"
 
 #undef DBGC_CLASS
 
 #define PERFCOUNT_MAX_LEN 256
 
+#define PERFCOUNTDIR   "perfmon"
+#define NAMES_DB       "names.tdb"
+#define DATA_DB                "data.tdb"
+
+/*********************************************************************
+*********************************************************************/
+
+static char* counters_directory( const char *dbname )
+{
+       static pstring fname;
+       fstring path;
+       
+       if ( !dbname )
+               return NULL;
+       
+       fstr_sprintf( path, "%s/%s", PERFCOUNTDIR, dbname );
+       
+       pstrcpy( fname, lock_path( path ) );
+       
+       return fname;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+void perfcount_init_keys( void )
+{
+       char *p = lock_path(PERFCOUNTDIR);
+
+       /* no registry keys; just create the perfmon directory */
+       
+       if ( !directory_exist( p, NULL ) )
+               mkdir( p, 0755 );
+       
+       return;
+}
+
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_base_index(void)
 {
-       pstring fname;
+       const char *fname = counters_directory( NAMES_DB );
        TDB_CONTEXT *names;
        TDB_DATA kbuf, dbuf;
        char key[] = "1";
        uint32 retval = 0;
        char buf[PERFCOUNT_MAX_LEN];
-       const char *counter_dir = lp_counters_dir();
-       
-
-       if ( !*counter_dir ) 
-               return 0;
-
-       pstr_sprintf( fname, "%s/names.tdb", counter_dir );
 
        names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
 
@@ -62,6 +117,9 @@ uint32 reg_perfcount_get_base_index(void)
        return 0;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_last_counter(uint32 base_index)
 {
        uint32 retval;
@@ -74,6 +132,9 @@ uint32 reg_perfcount_get_last_counter(uint32 base_index)
        return retval;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_last_help(uint32 last_counter)
 {
        uint32 retval;
@@ -86,6 +147,10 @@ uint32 reg_perfcount_get_last_help(uint32 last_counter)
        return retval;
 }
 
+
+/*********************************************************************
+*********************************************************************/
+
 static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb, 
                                               int keyval,
                                               char **retbuf,
@@ -145,20 +210,20 @@ static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb,
        return buffer_size;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
 {
        char *buf1 = NULL, *buf2 = NULL;
        uint32 buffer_size = 0;
        TDB_CONTEXT *names;
-       pstring fname;
+       const char *fname = counters_directory( NAMES_DB );
        int i;
 
        if(base_index == 0)
                return 0;
 
-       pstrcpy(fname, lp_counters_dir());
-       pstrcat(fname, "/names.tdb");
-
        names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
 
        if(names == NULL)
@@ -193,20 +258,20 @@ uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
        return buffer_size;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
 {
        char *buf1 = NULL, *buf2 = NULL;
        uint32 buffer_size = 0;
        TDB_CONTEXT *names;
-       pstring fname;
+       const char *fname = counters_directory( NAMES_DB );
        int i;
 
        if(base_index == 0)
                return 0;
 
-       pstrcpy(fname, lp_counters_dir());
-       pstrcat(fname, "/names.tdb");
-
        names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
 
        if(names == NULL)
@@ -243,6 +308,9 @@ uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
        return buffer_size;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static void _reg_perfcount_make_key(TDB_DATA *key,
                                    char *buf,
                                    int buflen,
@@ -261,6 +329,9 @@ static void _reg_perfcount_make_key(TDB_DATA *key,
        return;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_isparent(TDB_DATA data)
 {
        if(data.dsize > 0)
@@ -273,6 +344,9 @@ static BOOL _reg_perfcount_isparent(TDB_DATA data)
        return False;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_ischild(TDB_DATA data)
 {
        if(data.dsize > 0)
@@ -285,6 +359,9 @@ static BOOL _reg_perfcount_ischild(TDB_DATA data)
        return False;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
 {
        TDB_DATA key, data;
@@ -301,6 +378,9 @@ static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
        return (uint32)atoi(buf);
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_add_object(PERF_DATA_BLOCK *block,
                                      prs_struct *ps,
                                      int num,
@@ -341,15 +421,14 @@ static BOOL _reg_perfcount_add_object(PERF_DATA_BLOCK *block,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 BOOL _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
 {
        TDB_CONTEXT *counters;
-       pstring fname;
+       const char *fname = counters_directory( DATA_DB );
     
-       pstrcpy(fname, lp_counters_dir());
-       pstrcat(fname, "/data.tdb");
-
        counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
 
        if(counters == NULL)
@@ -365,6 +444,9 @@ BOOL _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
 {
        uint32 retval;
@@ -379,7 +461,10 @@ static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
        return retval;
 }
 
-static uint32 _reg_perfcount_compute_scale(long long int data)
+/*********************************************************************
+*********************************************************************/
+
+static uint32 _reg_perfcount_compute_scale(SMB_BIG_INT data)
 {
        int scale = 0;
        if(data == 0)
@@ -398,6 +483,9 @@ static uint32 _reg_perfcount_compute_scale(long long int data)
        return (uint32)scale;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
                                            prs_struct *ps,
                                            int CounterIndex,
@@ -408,7 +496,7 @@ static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
        char buf[PERFCOUNT_MAX_LEN];
        size_t dsize, padding;
        long int data32, dbuf[2];
-       long long int data64;
+       SMB_BIG_INT data64;
        uint32 counter_size;
 
        obj->counters[obj->NumCounters].DefaultScale = 0;
@@ -447,7 +535,7 @@ static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
                memcpy(buf, data.dptr, data.dsize);
                data32 = strtol(buf, NULL, 0);
                if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
-                       obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale((long long int)data32);
+                       obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale((SMB_BIG_INT)data32);
                else
                        obj->counters[obj->NumCounters].DefaultScale = 0;
                dbuf[0] = data32;
@@ -458,7 +546,7 @@ static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
                dsize = sizeof(data64);
                memset(buf, 0, PERFCOUNT_MAX_LEN);
                memcpy(buf, data.dptr, data.dsize);
-               data64 = strtoll(buf, NULL, 0);
+               data64 = atof(buf);
                if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
                        obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale(data64);
                else
@@ -504,6 +592,9 @@ static BOOL _reg_perfcount_get_counter_info(PERF_DATA_BLOCK *block,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 PERF_OBJECT_TYPE *_reg_perfcount_find_obj(PERF_DATA_BLOCK *block, int objind)
 {
        int i;
@@ -521,6 +612,9 @@ PERF_OBJECT_TYPE *_reg_perfcount_find_obj(PERF_DATA_BLOCK *block, int objind)
        return obj;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_add_counter(PERF_DATA_BLOCK *block,
                                       prs_struct *ps,
                                       int num,
@@ -582,6 +676,9 @@ static BOOL _reg_perfcount_add_counter(PERF_DATA_BLOCK *block,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 BOOL _reg_perfcount_get_instance_info(PERF_INSTANCE_DEFINITION *inst,
                                      prs_struct *ps,
                                      int instId,
@@ -662,6 +759,9 @@ BOOL _reg_perfcount_get_instance_info(PERF_INSTANCE_DEFINITION *inst,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 BOOL _reg_perfcount_add_instance(PERF_OBJECT_TYPE *obj,
                                 prs_struct *ps,
                                 int instInd,
@@ -689,6 +789,9 @@ BOOL _reg_perfcount_add_instance(PERF_OBJECT_TYPE *obj,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static int _reg_perfcount_assemble_global(PERF_DATA_BLOCK *block,
                                          prs_struct *ps,
                                          int base_index,
@@ -728,7 +831,10 @@ static int _reg_perfcount_assemble_global(PERF_DATA_BLOCK *block,
        return retval;
 }
 
-static BOOL _reg_perfcount_get_64(unsigned long long *retval,
+/*********************************************************************
+*********************************************************************/
+
+static BOOL _reg_perfcount_get_64(SMB_BIG_UINT *retval,
                                  TDB_CONTEXT *tdb,
                                  int key_part1,
                                  const char *key_part2)
@@ -749,23 +855,21 @@ static BOOL _reg_perfcount_get_64(unsigned long long *retval,
        memcpy(buf, data.dptr, data.dsize);
        free(data.dptr);
 
-       *retval = strtoll(buf, NULL, 0);
+       *retval = atof(buf);
 
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_init_data_block_perf(PERF_DATA_BLOCK *block,
                                                TDB_CONTEXT *names)
 {
-       unsigned long long PerfFreq, PerfTime, PerfTime100nSec;
+       SMB_BIG_UINT PerfFreq, PerfTime, PerfTime100nSec;
        TDB_CONTEXT *counters;
-       BOOL status;
-       pstring fname;
-    
-       status = False;
-    
-       pstrcpy(fname, lp_counters_dir());
-       pstrcat(fname, "/data.tdb");
+       BOOL status = False;
+       const char *fname = counters_directory( DATA_DB );
     
        counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
     
@@ -803,6 +907,9 @@ static BOOL _reg_perfcount_init_data_block_perf(PERF_DATA_BLOCK *block,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static void _reg_perfcount_init_data_block(PERF_DATA_BLOCK *block, prs_struct *ps, TDB_CONTEXT *names)
 {
        wpstring temp;
@@ -839,6 +946,9 @@ static void _reg_perfcount_init_data_block(PERF_DATA_BLOCK *block, prs_struct *p
        return;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static uint32 _reg_perfcount_perf_data_block_fixup(PERF_DATA_BLOCK *block, prs_struct *ps)
 {
        int obj, cnt, inst, pad, i;
@@ -923,20 +1033,20 @@ static uint32 _reg_perfcount_perf_data_block_fixup(PERF_DATA_BLOCK *block, prs_s
 
        return block->TotalByteLength;
 }
-    
+
+/*********************************************************************
+*********************************************************************/
+
 uint32 reg_perfcount_get_perf_data_block(uint32 base_index, 
                                         prs_struct *ps, 
                                         PERF_DATA_BLOCK *block,
                                         char *object_ids)
 {
        uint32 buffer_size = 0, last_counter;
-       pstring fname;
+       const char *fname = counters_directory( NAMES_DB );
        TDB_CONTEXT *names;
        int retval;
-
-       pstrcpy(fname, lp_counters_dir());
-       pstrcat(fname, "/names.tdb");
-
+       
        names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
 
        if(names == NULL)
@@ -966,6 +1076,9 @@ uint32 reg_perfcount_get_perf_data_block(uint32 base_index,
        return buffer_size + block->HeaderLength;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_perf_data_block(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
 {
        int i;
@@ -1017,6 +1130,9 @@ static BOOL _reg_perfcount_marshall_perf_data_block(prs_struct *ps, PERF_DATA_BL
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_perf_counters(prs_struct *ps,
                                                  PERF_OBJECT_TYPE object,
                                                  int depth)
@@ -1058,6 +1174,9 @@ static BOOL _reg_perfcount_marshall_perf_counters(prs_struct *ps,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_perf_counter_data(prs_struct *ps, 
                                                      PERF_COUNTER_BLOCK counter_data, 
                                                      int depth)
@@ -1078,6 +1197,9 @@ static BOOL _reg_perfcount_marshall_perf_counter_data(prs_struct *ps,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_perf_instances(prs_struct *ps,
                                                   PERF_OBJECT_TYPE object, 
                                                   int depth)
@@ -1116,6 +1238,9 @@ static BOOL _reg_perfcount_marshall_perf_instances(prs_struct *ps,
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_perf_objects(prs_struct *ps, PERF_DATA_BLOCK block, int depth)
 {
        int obj;
@@ -1183,6 +1308,9 @@ static BOOL _reg_perfcount_marshall_perf_objects(prs_struct *ps, PERF_DATA_BLOCK
        return True;
 }
 
+/*********************************************************************
+*********************************************************************/
+
 static BOOL _reg_perfcount_marshall_hkpd(prs_struct *ps, PERF_DATA_BLOCK block)
 {
        int depth = 0;
@@ -1193,6 +1321,10 @@ static BOOL _reg_perfcount_marshall_hkpd(prs_struct *ps, PERF_DATA_BLOCK block)
        }
        return False;
 }
+
+/*********************************************************************
+*********************************************************************/
+
 WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, char *object_ids)
 {
        /*
index 477bf4e26993835e48d28ff6ff9891cb7ee2cbba..5c87225f57304e73c592d88d57dc2a8c329355b9 100644 (file)
@@ -71,6 +71,7 @@ struct service_display_info common_unix_svcs[] = {
   { "apache",        NULL, "HTTP Server", NULL },
   { "autofs",        NULL, "Automounter", NULL },
   { "squid",         NULL, "Web Cache Proxy ", NULL },
+  { "perfcountd",    NULL, "Performance Monitoring Daemon", NULL },
   { NULL, NULL, NULL, NULL }
 };
 
index 7397c88d958905726cf53abd20f6a9fbe84a1629..289fb59fea331d0ee991e743859e9a79c8add57f 100644 (file)
@@ -117,11 +117,14 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
                return werror_to_ntstatus(result);
        }
        
-       result = rpccli_reg_open_entry(pipe_hnd, mem_ctx, &pol_hive, subpath, MAXIMUM_ALLOWED_ACCESS, &pol_key );
-       if ( !W_ERROR_IS_OK(result) ) {
-               d_printf("Unable to open [%s]\n", argv[0]);
-               return werror_to_ntstatus(result);
+       if ( strlen( subpath ) != 0 ) {
+               result = rpccli_reg_open_entry(pipe_hnd, mem_ctx, &pol_hive, subpath, MAXIMUM_ALLOWED_ACCESS, &pol_key );
+               if ( !W_ERROR_IS_OK(result) ) {
+                       d_printf("Unable to open [%s]\n", argv[0]);
+                       return werror_to_ntstatus(result);
+               }
        }
+               memcpy( &pol_key, &pol_hive, sizeof(POLICY_HND) );
        
        /* get the subkeys */
        
@@ -183,7 +186,8 @@ static NTSTATUS rpc_registry_enumerate_internal(const DOM_SID *domain_sid,
 out:
        /* cleanup */
        
-       rpccli_reg_close(pipe_hnd, mem_ctx, &pol_key );
+       if ( strlen( subpath ) != 0 )
+               rpccli_reg_close(pipe_hnd, mem_ctx, &pol_key );
        rpccli_reg_close(pipe_hnd, mem_ctx, &pol_hive );
 
        return werror_to_ntstatus(result);