1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source3/registry/reg_perfcount.c

1411 lines
42 KiB
C
Raw Normal View History

/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_REGISTRY
#define PERFCOUNT_MAX_LEN 256
#define PERFCOUNTDIR "perfmon"
#define NAMES_DB "names.tdb"
#define DATA_DB "data.tdb"
struct PERF_OBJECT_TYPE *_reg_perfcount_find_obj(struct PERF_DATA_BLOCK *block, int objind);
/*********************************************************************
*********************************************************************/
static char *counters_directory(const char *dbname)
{
char *path = NULL;
char *ret = NULL;
TALLOC_CTX *ctx = talloc_tos();
path = talloc_asprintf(ctx, "%s/%s", PERFCOUNTDIR, dbname);
if (!path) {
return NULL;
}
ret = talloc_strdup(ctx, state_path(path));
TALLOC_FREE(path);
return ret;
}
/*********************************************************************
*********************************************************************/
void perfcount_init_keys( void )
{
char *p = state_path(PERFCOUNTDIR);
/* no registry keys; just create the perfmon directory */
2009-02-14 20:49:13 +03:00
if ( !directory_exist( p ) )
mkdir( p, 0755 );
2009-02-14 20:49:13 +03:00
return;
}
/*********************************************************************
*********************************************************************/
uint32 reg_perfcount_get_base_index(void)
{
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];
names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
if ( !names ) {
DEBUG(1, ("reg_perfcount_get_base_index: unable to open [%s].\n", fname));
return 0;
}
/* needs to read the value of key "1" from the counter_names.tdb file, as that is
where the total number of counters is stored. We're assuming no holes in the
enumeration.
The format for the counter_names.tdb file is:
key value
1 num_counters
2 perf_counter1
3 perf_counter1_help
4 perf_counter2
5 perf_counter2_help
even_num perf_counter<even_num>
even_num+1 perf_counter<even_num>_help
and so on.
So last_counter becomes num_counters*2, and last_help will be last_counter+1 */
kbuf = string_tdb_data(key);
dbuf = tdb_fetch(names, kbuf);
if(dbuf.dptr == NULL)
{
DEBUG(1, ("reg_perfcount_get_base_index: failed to find key \'1\' in [%s].\n", fname));
tdb_close(names);
return 0;
}
else
{
tdb_close(names);
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, dbuf.dptr, dbuf.dsize);
retval = (uint32)atoi(buf);
SAFE_FREE(dbuf.dptr);
return retval;
}
return 0;
}
/*********************************************************************
*********************************************************************/
uint32 reg_perfcount_get_last_counter(uint32 base_index)
{
uint32 retval;
if(base_index == 0)
retval = 0;
else
retval = base_index * 2;
return retval;
}
/*********************************************************************
*********************************************************************/
uint32 reg_perfcount_get_last_help(uint32 last_counter)
{
uint32 retval;
if(last_counter == 0)
retval = 0;
else
retval = last_counter + 1;
return retval;
}
/*********************************************************************
*********************************************************************/
static uint32 _reg_perfcount_multi_sz_from_tdb(TDB_CONTEXT *tdb,
int keyval,
char **retbuf,
uint32 buffer_size)
{
TDB_DATA kbuf, dbuf;
char temp[256];
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
char *buf1 = *retbuf;
uint32 working_size = 0;
DATA_BLOB name_index, name;
memset(temp, 0, sizeof(temp));
snprintf(temp, sizeof(temp), "%d", keyval);
kbuf = string_tdb_data(temp);
dbuf = tdb_fetch(tdb, kbuf);
if(dbuf.dptr == NULL)
{
/* If a key isn't there, just bypass it -- this really shouldn't
happen unless someone's mucking around with the tdb */
DEBUG(3, ("_reg_perfcount_multi_sz_from_tdb: failed to find key [%s] in [%s].\n",
temp, tdb_name(tdb)));
return buffer_size;
}
/* First encode the name_index */
working_size = (kbuf.dsize + 1)*sizeof(uint16);
buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if(!buf1) {
buffer_size = 0;
return buffer_size;
}
push_reg_sz(talloc_tos(), NULL, &name_index, (const char *)kbuf.dptr);
memcpy(buf1+buffer_size, (char *)name_index.data, working_size);
buffer_size += working_size;
/* Now encode the actual name */
working_size = (dbuf.dsize + 1)*sizeof(uint16);
buf1 = (char *)SMB_REALLOC(buf1, buffer_size + working_size);
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if(!buf1) {
buffer_size = 0;
return buffer_size;
}
memset(temp, 0, sizeof(temp));
memcpy(temp, dbuf.dptr, dbuf.dsize);
SAFE_FREE(dbuf.dptr);
push_reg_sz(talloc_tos(), NULL, &name, temp);
memcpy(buf1+buffer_size, (char *)name.data, working_size);
buffer_size += working_size;
*retbuf = buf1;
return buffer_size;
}
/*********************************************************************
*********************************************************************/
uint32 reg_perfcount_get_counter_help(uint32 base_index, char **retbuf)
{
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
char *buf1 = NULL;
uint32 buffer_size = 0;
TDB_CONTEXT *names;
const char *fname = counters_directory( NAMES_DB );
int i;
if(base_index == 0)
return 0;
names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
if(names == NULL)
{
DEBUG(1, ("reg_perfcount_get_counter_help: unable to open [%s].\n", fname));
return 0;
}
for(i = 1; i <= base_index; i++)
{
buffer_size = _reg_perfcount_multi_sz_from_tdb(names, (i*2)+1, retbuf, buffer_size);
}
tdb_close(names);
/* Now terminate the MULTI_SZ with a double unicode NULL */
buf1 = *retbuf;
buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if(!buf1) {
buffer_size = 0;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
} else {
buf1[buffer_size++] = '\0';
buf1[buffer_size++] = '\0';
}
*retbuf = buf1;
return buffer_size;
}
/*********************************************************************
*********************************************************************/
uint32 reg_perfcount_get_counter_names(uint32 base_index, char **retbuf)
{
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
char *buf1 = NULL;
uint32 buffer_size = 0;
TDB_CONTEXT *names;
const char *fname = counters_directory( NAMES_DB );
int i;
if(base_index == 0)
return 0;
names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
if(names == NULL)
{
DEBUG(1, ("reg_perfcount_get_counter_names: unable to open [%s].\n", fname));
return 0;
}
buffer_size = _reg_perfcount_multi_sz_from_tdb(names, 1, retbuf, buffer_size);
for(i = 1; i <= base_index; i++)
{
buffer_size = _reg_perfcount_multi_sz_from_tdb(names, i*2, retbuf, buffer_size);
}
tdb_close(names);
/* Now terminate the MULTI_SZ with a double unicode NULL */
buf1 = *retbuf;
buf1 = (char *)SMB_REALLOC(buf1, buffer_size + 2);
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if(!buf1) {
buffer_size = 0;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
} else {
buf1[buffer_size++] = '\0';
buf1[buffer_size++] = '\0';
}
*retbuf=buf1;
return buffer_size;
}
/*********************************************************************
*********************************************************************/
static void _reg_perfcount_make_key(TDB_DATA *key,
char *buf,
int buflen,
int key_part1,
const char *key_part2)
{
memset(buf, 0, buflen);
if(key_part2 != NULL)
snprintf(buf, buflen,"%d%s", key_part1, key_part2);
else
snprintf(buf, buflen, "%d", key_part1);
*key = string_tdb_data(buf);
return;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_isparent(TDB_DATA data)
{
if(data.dsize > 0)
{
if(data.dptr[0] == 'p')
return True;
else
return False;
}
return False;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_ischild(TDB_DATA data)
{
if(data.dsize > 0)
{
if(data.dptr[0] == 'c')
return True;
else
return False;
}
return False;
}
/*********************************************************************
*********************************************************************/
static uint32 _reg_perfcount_get_numinst(int objInd, TDB_CONTEXT *names)
{
TDB_DATA key, data;
char buf[PERFCOUNT_MAX_LEN];
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, objInd, "inst");
data = tdb_fetch(names, key);
if(data.dptr == NULL)
return (uint32)PERF_NO_INSTANCES;
2009-02-14 20:49:13 +03:00
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
SAFE_FREE(data.dptr);
return (uint32)atoi(buf);
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static bool _reg_perfcount_add_instance(struct PERF_OBJECT_TYPE *obj,
TALLOC_CTX *mem_ctx,
int instInd,
TDB_CONTEXT *names);
static bool _reg_perfcount_add_object(struct PERF_DATA_BLOCK *block,
TALLOC_CTX *mem_ctx,
int num,
TDB_DATA data,
TDB_CONTEXT *names)
{
int i;
bool success = True;
struct PERF_OBJECT_TYPE *obj;
block->objects = (struct PERF_OBJECT_TYPE *)TALLOC_REALLOC_ARRAY(mem_ctx,
block->objects,
struct PERF_OBJECT_TYPE,
block->NumObjectTypes+1);
if(block->objects == NULL)
return False;
obj = &(block->objects[block->NumObjectTypes]);
memset((void *)&(block->objects[block->NumObjectTypes]), 0, sizeof(struct PERF_OBJECT_TYPE));
block->objects[block->NumObjectTypes].ObjectNameTitleIndex = num;
block->objects[block->NumObjectTypes].ObjectNameTitlePointer = 0;
block->objects[block->NumObjectTypes].ObjectHelpTitleIndex = num+1;
block->objects[block->NumObjectTypes].ObjectHelpTitlePointer = 0;
block->objects[block->NumObjectTypes].NumCounters = 0;
block->objects[block->NumObjectTypes].DefaultCounter = 0;
block->objects[block->NumObjectTypes].NumInstances = _reg_perfcount_get_numinst(num, names);
block->objects[block->NumObjectTypes].counters = NULL;
block->objects[block->NumObjectTypes].instances = NULL;
block->objects[block->NumObjectTypes].counter_data.ByteLength = sizeof(uint32);
block->objects[block->NumObjectTypes].counter_data.data = NULL;
block->objects[block->NumObjectTypes].DetailLevel = PERF_DETAIL_NOVICE;
block->NumObjectTypes+=1;
for(i = 0; i < (int)obj->NumInstances; i++) {
success = _reg_perfcount_add_instance(obj, mem_ctx, i, names);
}
return success;
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static bool _reg_perfcount_get_counter_data(TDB_DATA key, TDB_DATA *data)
{
TDB_CONTEXT *counters;
const char *fname = counters_directory( DATA_DB );
2009-02-14 20:49:13 +03:00
counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
if(counters == NULL)
{
DEBUG(1, ("reg_perfcount_get_counter_data: unable to open [%s].\n", fname));
return False;
}
*data = tdb_fetch(counters, key);
2009-02-14 20:49:13 +03:00
tdb_close(counters);
return True;
}
/*********************************************************************
*********************************************************************/
static uint32 _reg_perfcount_get_size_field(uint32 CounterType)
{
uint32 retval;
retval = CounterType;
/* First mask out reserved lower 8 bits */
retval = retval & 0xFFFFFF00;
retval = retval << 22;
retval = retval >> 22;
return retval;
}
/*********************************************************************
*********************************************************************/
static uint32 _reg_perfcount_compute_scale(int64_t data)
{
int scale = 0;
if(data == 0)
return scale;
while(data > 100)
{
data /= 10;
scale--;
}
while(data < 10)
{
data *= 10;
scale++;
}
return (uint32)scale;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_get_counter_info(struct PERF_DATA_BLOCK *block,
TALLOC_CTX *mem_ctx,
int CounterIndex,
struct PERF_OBJECT_TYPE *obj,
TDB_CONTEXT *names)
{
TDB_DATA key, data;
char buf[PERFCOUNT_MAX_LEN];
size_t dsize, padding;
long int data32, dbuf[2];
int64_t data64;
uint32 counter_size;
obj->counters[obj->NumCounters].DefaultScale = 0;
dbuf[0] = dbuf[1] = 0;
padding = 0;
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "type");
data = tdb_fetch(names, key);
if(data.dptr == NULL)
{
DEBUG(3, ("_reg_perfcount_get_counter_info: No type data for counter [%d].\n", CounterIndex));
return False;
}
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
obj->counters[obj->NumCounters].CounterType = atoi(buf);
DEBUG(10, ("_reg_perfcount_get_counter_info: Got type [%d] for counter [%d].\n",
obj->counters[obj->NumCounters].CounterType, CounterIndex));
SAFE_FREE(data.dptr);
/* Fetch the actual data */
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, CounterIndex, "");
_reg_perfcount_get_counter_data(key, &data);
if(data.dptr == NULL)
{
DEBUG(3, ("_reg_perfcount_get_counter_info: No counter data for counter [%d].\n", CounterIndex));
return False;
}
2009-02-14 20:49:13 +03:00
counter_size = _reg_perfcount_get_size_field(obj->counters[obj->NumCounters].CounterType);
if(counter_size == PERF_SIZE_DWORD)
{
dsize = sizeof(data32);
memset(buf, 0, PERFCOUNT_MAX_LEN);
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((int64_t)data32);
else
obj->counters[obj->NumCounters].DefaultScale = 0;
dbuf[0] = data32;
padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
}
else if(counter_size == PERF_SIZE_LARGE)
{
dsize = sizeof(data64);
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
data64 = atof(buf);
if((obj->counters[obj->NumCounters].CounterType & 0x00000F00) == PERF_TYPE_NUMBER)
obj->counters[obj->NumCounters].DefaultScale = _reg_perfcount_compute_scale(data64);
else
obj->counters[obj->NumCounters].DefaultScale = 0;
memcpy((void *)dbuf, (const void *)&data64, dsize);
padding = (dsize - (obj->counter_data.ByteLength%dsize)) % dsize;
}
else /* PERF_SIZE_VARIABLE_LEN */
{
dsize = data.dsize;
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
}
SAFE_FREE(data.dptr);
obj->counter_data.ByteLength += dsize + padding;
obj->counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
obj->counter_data.data,
uint8,
obj->counter_data.ByteLength - sizeof(uint32));
if(obj->counter_data.data == NULL)
return False;
if(dbuf[0] != 0 || dbuf[1] != 0)
{
memcpy((void *)(obj->counter_data.data +
(obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
(const void *)dbuf, dsize);
}
else
{
/* Handling PERF_SIZE_VARIABLE_LEN */
memcpy((void *)(obj->counter_data.data +
(obj->counter_data.ByteLength - (sizeof(uint32) + dsize))),
(const void *)buf, dsize);
}
obj->counters[obj->NumCounters].CounterOffset = obj->counter_data.ByteLength - dsize;
if(obj->counters[obj->NumCounters].CounterOffset % dsize != 0)
{
DEBUG(3,("Improperly aligned counter [%d]\n", obj->NumCounters));
}
obj->counters[obj->NumCounters].CounterSize = dsize;
return True;
}
/*********************************************************************
*********************************************************************/
struct PERF_OBJECT_TYPE *_reg_perfcount_find_obj(struct PERF_DATA_BLOCK *block, int objind)
{
int i;
struct PERF_OBJECT_TYPE *obj = NULL;
for(i = 0; i < block->NumObjectTypes; i++)
{
if(block->objects[i].ObjectNameTitleIndex == objind)
{
obj = &(block->objects[i]);
}
}
return obj;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_add_counter(struct PERF_DATA_BLOCK *block,
TALLOC_CTX *mem_ctx,
int num,
TDB_DATA data,
TDB_CONTEXT *names)
{
char *begin, *end, *start, *stop;
int parent;
struct PERF_OBJECT_TYPE *obj;
bool success = True;
char buf[PERFCOUNT_MAX_LEN];
2009-02-14 20:49:13 +03:00
obj = NULL;
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
begin = index(buf, '[');
end = index(buf, ']');
if(begin == NULL || end == NULL)
return False;
start = begin+1;
while(start < end) {
stop = index(start, ',');
if(stop == NULL)
stop = end;
*stop = '\0';
parent = atoi(start);
obj = _reg_perfcount_find_obj(block, parent);
if(obj == NULL) {
/* At this point we require that the parent object exist.
This can probably be handled better at some later time */
DEBUG(3, ("_reg_perfcount_add_counter: Could not find parent object [%d] for counter [%d].\n",
parent, num));
return False;
}
obj->counters = (struct PERF_COUNTER_DEFINITION *)TALLOC_REALLOC_ARRAY(mem_ctx,
obj->counters,
struct PERF_COUNTER_DEFINITION,
obj->NumCounters+1);
if(obj->counters == NULL)
return False;
memset((void *)&(obj->counters[obj->NumCounters]), 0, sizeof(struct PERF_COUNTER_DEFINITION));
obj->counters[obj->NumCounters].CounterNameTitleIndex=num;
obj->counters[obj->NumCounters].CounterHelpTitleIndex=num+1;
obj->counters[obj->NumCounters].DetailLevel = PERF_DETAIL_NOVICE;
obj->counters[obj->NumCounters].ByteLength = sizeof(struct PERF_COUNTER_DEFINITION);
success = _reg_perfcount_get_counter_info(block, mem_ctx, num, obj, names);
obj->NumCounters += 1;
start = stop + 1;
}
2009-02-14 20:49:13 +03:00
/* Handle case of Objects/Counters without any counter data, which would suggest
that the required instances are not there yet, so change NumInstances from
PERF_NO_INSTANCES to 0 */
return success;
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static bool _reg_perfcount_get_instance_info(struct PERF_INSTANCE_DEFINITION *inst,
TALLOC_CTX *mem_ctx,
int instId,
struct PERF_OBJECT_TYPE *obj,
TDB_CONTEXT *names)
{
TDB_DATA key, data;
char buf[PERFCOUNT_MAX_LEN], temp[PERFCOUNT_MAX_LEN];
smb_ucs2_t *name = NULL;
int pad;
/* First grab the instance data from the data file */
memset(temp, 0, PERFCOUNT_MAX_LEN);
snprintf(temp, PERFCOUNT_MAX_LEN, "i%d", instId);
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
if (!_reg_perfcount_get_counter_data(key, &data)) {
DEBUG(3, ("_reg_perfcount_get_counter_data failed\n"));
return false;
}
if(data.dptr == NULL)
{
DEBUG(3, ("_reg_perfcount_get_instance_info: No instance data for instance [%s].\n",
buf));
return False;
}
inst->counter_data.ByteLength = data.dsize + sizeof(inst->counter_data.ByteLength);
inst->counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
inst->counter_data.data,
uint8,
data.dsize);
if(inst->counter_data.data == NULL)
return False;
memset(inst->counter_data.data, 0, data.dsize);
memcpy(inst->counter_data.data, data.dptr, data.dsize);
SAFE_FREE(data.dptr);
/* Fetch instance name */
memset(temp, 0, PERFCOUNT_MAX_LEN);
snprintf(temp, PERFCOUNT_MAX_LEN, "i%dname", instId);
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, obj->ObjectNameTitleIndex, temp);
data = tdb_fetch(names, key);
if(data.dptr == NULL)
{
/* Not actually an error, but possibly unintended? -- just logging FYI */
DEBUG(3, ("_reg_perfcount_get_instance_info: No instance name for instance [%s].\n",
buf));
inst->NameLength = 0;
}
else
{
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, MIN(PERFCOUNT_MAX_LEN-1,data.dsize));
buf[PERFCOUNT_MAX_LEN-1] = '\0';
inst->NameLength = rpcstr_push_talloc(mem_ctx, &name, buf);
if (inst->NameLength == (uint32_t)-1 || !name) {
SAFE_FREE(data.dptr);
return False;
}
inst->data = TALLOC_REALLOC_ARRAY(mem_ctx,
inst->data,
uint8,
inst->NameLength);
if (inst->data == NULL) {
SAFE_FREE(data.dptr);
return False;
}
memcpy(inst->data, name, inst->NameLength);
SAFE_FREE(data.dptr);
}
inst->ParentObjectTitleIndex = 0;
inst->ParentObjectTitlePointer = 0;
inst->UniqueID = PERF_NO_UNIQUE_ID;
inst->NameOffset = 6 * sizeof(uint32);
2009-02-14 20:49:13 +03:00
inst->ByteLength = inst->NameOffset + inst->NameLength;
/* Need to be aligned on a 64-bit boundary here for counter_data */
if((pad = (inst->ByteLength % 8)))
{
pad = 8 - pad;
inst->data = TALLOC_REALLOC_ARRAY(mem_ctx,
inst->data,
uint8,
inst->NameLength + pad);
memset(inst->data + inst->NameLength, 0, pad);
inst->ByteLength += pad;
}
return True;
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static bool _reg_perfcount_add_instance(struct PERF_OBJECT_TYPE *obj,
TALLOC_CTX *mem_ctx,
int instInd,
TDB_CONTEXT *names)
{
struct PERF_INSTANCE_DEFINITION *inst;
if(obj->instances == NULL) {
obj->instances = TALLOC_REALLOC_ARRAY(mem_ctx,
obj->instances,
struct PERF_INSTANCE_DEFINITION,
obj->NumInstances);
}
if(obj->instances == NULL)
return False;
2009-02-14 20:49:13 +03:00
memset(&(obj->instances[instInd]), 0, sizeof(struct PERF_INSTANCE_DEFINITION));
inst = &(obj->instances[instInd]);
return _reg_perfcount_get_instance_info(inst, mem_ctx, instInd, obj, names);
}
/*********************************************************************
*********************************************************************/
static int _reg_perfcount_assemble_global(struct PERF_DATA_BLOCK *block,
TALLOC_CTX *mem_ctx,
int base_index,
TDB_CONTEXT *names)
{
bool success;
int i, j, retval = 0;
char keybuf[PERFCOUNT_MAX_LEN];
TDB_DATA key, data;
for(i = 1; i <= base_index; i++)
{
j = i*2;
_reg_perfcount_make_key(&key, keybuf, PERFCOUNT_MAX_LEN, j, "rel");
data = tdb_fetch(names, key);
if(data.dptr != NULL)
{
if(_reg_perfcount_isparent(data))
success = _reg_perfcount_add_object(block, mem_ctx, j, data, names);
else if(_reg_perfcount_ischild(data))
success = _reg_perfcount_add_counter(block, mem_ctx, j, data, names);
else
{
DEBUG(3, ("Bogus relationship [%s] for counter [%d].\n", data.dptr, j));
success = False;
}
if(success == False)
{
DEBUG(3, ("_reg_perfcount_assemble_global: Failed to add new relationship for counter [%d].\n", j));
retval = -1;
}
SAFE_FREE(data.dptr);
}
else
DEBUG(3, ("NULL relationship for counter [%d] using key [%s].\n", j, keybuf));
}
return retval;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_get_64(uint64_t *retval,
TDB_CONTEXT *tdb,
int key_part1,
const char *key_part2)
{
TDB_DATA key, data;
char buf[PERFCOUNT_MAX_LEN];
_reg_perfcount_make_key(&key, buf, PERFCOUNT_MAX_LEN, key_part1, key_part2);
data = tdb_fetch(tdb, key);
if(data.dptr == NULL)
{
DEBUG(3,("_reg_perfcount_get_64: No data found for key [%s].\n", key.dptr));
return False;
}
memset(buf, 0, PERFCOUNT_MAX_LEN);
memcpy(buf, data.dptr, data.dsize);
SAFE_FREE(data.dptr);
*retval = atof(buf);
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_init_data_block_perf(struct PERF_DATA_BLOCK *block,
TDB_CONTEXT *names)
{
uint64_t PerfFreq, PerfTime, PerfTime100nSec;
TDB_CONTEXT *counters;
bool status = False;
const char *fname = counters_directory( DATA_DB );
2009-02-14 20:49:13 +03:00
counters = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
2009-02-14 20:49:13 +03:00
if(counters == NULL)
{
DEBUG(1, ("reg_perfcount_init_data_block_perf: unable to open [%s].\n", fname));
return False;
}
2009-02-14 20:49:13 +03:00
status = _reg_perfcount_get_64(&PerfFreq, names, 0, "PerfFreq");
if(status == False)
{
tdb_close(counters);
return status;
}
memcpy((void *)&(block->PerfFreq), (const void *)&PerfFreq, sizeof(PerfFreq));
status = _reg_perfcount_get_64(&PerfTime, counters, 0, "PerfTime");
if(status == False)
{
tdb_close(counters);
return status;
}
memcpy((void *)&(block->PerfTime), (const void *)&PerfTime, sizeof(PerfTime));
status = _reg_perfcount_get_64(&PerfTime100nSec, counters, 0, "PerfTime100nSec");
if(status == False)
{
tdb_close(counters);
return status;
}
memcpy((void *)&(block->PerfTime100nSec), (const void *)&PerfTime100nSec, sizeof(PerfTime100nSec));
tdb_close(counters);
return True;
}
/*******************************************************************
********************************************************************/
static bool make_systemtime(struct SYSTEMTIME *systime, struct tm *unixtime)
{
systime->year=unixtime->tm_year+1900;
systime->month=unixtime->tm_mon+1;
systime->dayofweek=unixtime->tm_wday;
systime->day=unixtime->tm_mday;
systime->hour=unixtime->tm_hour;
systime->minute=unixtime->tm_min;
systime->second=unixtime->tm_sec;
systime->milliseconds=0;
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_init_data_block(struct PERF_DATA_BLOCK *block,
TALLOC_CTX *mem_ctx, TDB_CONTEXT *names,
bool bigendian_data)
{
smb_ucs2_t *temp = NULL;
time_t tm;
if (rpcstr_push_talloc(mem_ctx, &temp, "PERF")==(size_t)-1) {
return false;
}
if (!temp) {
return false;
}
memcpy(block->Signature, temp, strlen_w(temp) *2);
if(bigendian_data)
block->LittleEndian = 0;
else
block->LittleEndian = 1;
block->Version = 1;
block->Revision = 1;
block->TotalByteLength = 0;
block->NumObjectTypes = 0;
block->DefaultObject = -1;
block->objects = NULL;
tm = time(NULL);
make_systemtime(&(block->SystemTime), gmtime(&tm));
_reg_perfcount_init_data_block_perf(block, names);
memset(temp, 0, sizeof(temp));
rpcstr_push((void *)temp, global_myname(), sizeof(temp), STR_TERMINATE);
block->SystemNameLength = (strlen_w(temp) * 2) + 2;
block->data = TALLOC_ZERO_ARRAY(mem_ctx, uint8, block->SystemNameLength + (8 - (block->SystemNameLength % 8)));
if (block->data == NULL) {
return False;
}
memcpy(block->data, temp, block->SystemNameLength);
block->SystemNameOffset = sizeof(struct PERF_DATA_BLOCK) - sizeof(block->objects) - sizeof(block->data);
block->HeaderLength = block->SystemNameOffset + block->SystemNameLength;
/* Make sure to adjust for 64-bit alignment for when we finish writing the system name,
so that the PERF_OBJECT_TYPE struct comes out 64-bit aligned */
block->HeaderLength += 8 - (block->HeaderLength % 8);
return True;
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static uint32 _reg_perfcount_perf_data_block_fixup(struct PERF_DATA_BLOCK *block, TALLOC_CTX *mem_ctx)
{
int obj, cnt, inst, pad, i;
struct PERF_OBJECT_TYPE *object;
struct PERF_INSTANCE_DEFINITION *instance;
struct PERF_COUNTER_DEFINITION *counter;
struct PERF_COUNTER_BLOCK *counter_data;
char *temp = NULL, *src_addr, *dst_addr;
block->TotalByteLength = 0;
object = block->objects;
for(obj = 0; obj < block->NumObjectTypes; obj++)
{
object[obj].TotalByteLength = 0;
object[obj].DefinitionLength = 0;
instance = object[obj].instances;
counter = object[obj].counters;
for(cnt = 0; cnt < object[obj].NumCounters; cnt++)
{
object[obj].TotalByteLength += counter[cnt].ByteLength;
object[obj].DefinitionLength += counter[cnt].ByteLength;
}
if(object[obj].NumInstances != PERF_NO_INSTANCES)
{
for(inst = 0; inst < object[obj].NumInstances; inst++)
{
instance = &(object[obj].instances[inst]);
object[obj].TotalByteLength += instance->ByteLength;
counter_data = &(instance->counter_data);
counter = &(object[obj].counters[object[obj].NumCounters - 1]);
counter_data->ByteLength = counter->CounterOffset + counter->CounterSize + sizeof(counter_data->ByteLength);
2009-10-01 12:21:17 +04:00
temp = TALLOC_REALLOC_ARRAY(mem_ctx,
temp,
char,
counter_data->ByteLength- sizeof(counter_data->ByteLength));
if (temp == NULL) {
return 0;
}
memset(temp, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength));
src_addr = (char *)counter_data->data;
for(i = 0; i < object[obj].NumCounters; i++)
{
counter = &(object[obj].counters[i]);
dst_addr = temp + counter->CounterOffset - sizeof(counter_data->ByteLength);
memcpy(dst_addr, src_addr, counter->CounterSize);
src_addr += counter->CounterSize;
}
/* Make sure to be 64-bit aligned */
if((pad = (counter_data->ByteLength % 8)))
{
pad = 8 - pad;
}
2009-10-01 12:21:17 +04:00
counter_data->data = TALLOC_REALLOC_ARRAY(mem_ctx,
counter_data->data,
uint8,
counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
if (counter_data->data == NULL) {
return 0;
}
memset(counter_data->data, 0, counter_data->ByteLength - sizeof(counter_data->ByteLength) + pad);
memcpy(counter_data->data, temp, counter_data->ByteLength - sizeof(counter_data->ByteLength));
counter_data->ByteLength += pad;
object[obj].TotalByteLength += counter_data->ByteLength;
}
}
else
{
/* Need to be 64-bit aligned at the end of the counter_data block, so pad counter_data to a 64-bit boundary,
so that the next PERF_OBJECT_TYPE can start on a 64-bit alignment */
if((pad = (object[obj].counter_data.ByteLength % 8)))
{
pad = 8 - pad;
2009-10-01 12:21:17 +04:00
object[obj].counter_data.data = TALLOC_REALLOC_ARRAY(mem_ctx,
object[obj].counter_data.data,
uint8,
object[obj].counter_data.ByteLength + pad);
memset((void *)(object[obj].counter_data.data + object[obj].counter_data.ByteLength), 0, pad);
object[obj].counter_data.ByteLength += pad;
}
object[obj].TotalByteLength += object[obj].counter_data.ByteLength;
}
object[obj].HeaderLength = sizeof(*object) - (sizeof(counter) + sizeof(instance) + sizeof(struct PERF_COUNTER_BLOCK));
object[obj].TotalByteLength += object[obj].HeaderLength;
object[obj].DefinitionLength += object[obj].HeaderLength;
2009-02-14 20:49:13 +03:00
block->TotalByteLength += object[obj].TotalByteLength;
}
return block->TotalByteLength;
}
/*********************************************************************
*********************************************************************/
2009-10-01 12:21:17 +04:00
static uint32 reg_perfcount_get_perf_data_block(uint32 base_index,
TALLOC_CTX *mem_ctx,
struct PERF_DATA_BLOCK *block,
const char *object_ids,
bool bigendian_data)
{
uint32 buffer_size = 0;
const char *fname = counters_directory( NAMES_DB );
TDB_CONTEXT *names;
int retval = 0;
2009-02-14 20:49:13 +03:00
names = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDONLY, 0444);
if(names == NULL)
{
DEBUG(1, ("reg_perfcount_get_perf_data_block: unable to open [%s].\n", fname));
return 0;
}
2009-10-01 12:21:17 +04:00
if (!_reg_perfcount_init_data_block(block, mem_ctx, names, bigendian_data)) {
DEBUG(0, ("_reg_perfcount_init_data_block failed\n"));
tdb_close(names);
return 0;
}
reg_perfcount_get_last_counter(base_index);
2009-02-14 20:49:13 +03:00
if(object_ids == NULL)
{
/* we're getting a request for "Global" here */
2009-10-01 12:21:17 +04:00
retval = _reg_perfcount_assemble_global(block, mem_ctx, base_index, names);
}
else
{
/* we're getting a request for a specific set of PERF_OBJECT_TYPES */
2009-10-01 12:21:17 +04:00
retval = _reg_perfcount_assemble_global(block, mem_ctx, base_index, names);
}
2009-10-01 12:21:17 +04:00
buffer_size = _reg_perfcount_perf_data_block_fixup(block, mem_ctx);
tdb_close(names);
if (retval == -1) {
return 0;
}
return buffer_size + block->HeaderLength;
}
/*******************************************************************
********************************************************************/
static bool smb_io_system_time(const char *desc, prs_struct *ps, int depth, struct SYSTEMTIME *systime)
{
if(!prs_uint16("year", ps, depth, &systime->year))
return False;
if(!prs_uint16("month", ps, depth, &systime->month))
return False;
if(!prs_uint16("dayofweek", ps, depth, &systime->dayofweek))
return False;
if(!prs_uint16("day", ps, depth, &systime->day))
return False;
if(!prs_uint16("hour", ps, depth, &systime->hour))
return False;
if(!prs_uint16("minute", ps, depth, &systime->minute))
return False;
if(!prs_uint16("second", ps, depth, &systime->second))
return False;
if(!prs_uint16("milliseconds", ps, depth, &systime->milliseconds))
return False;
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_marshall_perf_data_block(prs_struct *ps, struct PERF_DATA_BLOCK block, int depth)
{
int i;
prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_data_block");
depth++;
if(!prs_align(ps))
return False;
for(i = 0; i < 4; i++)
{
if(!prs_uint16("Signature", ps, depth, &block.Signature[i]))
return False;
}
if(!prs_uint32("Little Endian", ps, depth, &block.LittleEndian))
return False;
if(!prs_uint32("Version", ps, depth, &block.Version))
return False;
if(!prs_uint32("Revision", ps, depth, &block.Revision))
return False;
if(!prs_uint32("TotalByteLength", ps, depth, &block.TotalByteLength))
return False;
if(!prs_uint32("HeaderLength", ps, depth, &block.HeaderLength))
return False;
if(!prs_uint32("NumObjectTypes", ps, depth, &block.NumObjectTypes))
return False;
if(!prs_uint32("DefaultObject", ps, depth, &block.DefaultObject))
return False;
if(!smb_io_system_time("SystemTime", ps, depth, &block.SystemTime))
return False;
if(!prs_uint32("Padding", ps, depth, &block.Padding))
return False;
if(!prs_align_uint64(ps))
return False;
if(!prs_uint64("PerfTime", ps, depth, &block.PerfTime))
return False;
if(!prs_uint64("PerfFreq", ps, depth, &block.PerfFreq))
return False;
if(!prs_uint64("PerfTime100nSec", ps, depth, &block.PerfTime100nSec))
return False;
if(!prs_uint32("SystemNameLength", ps, depth, &block.SystemNameLength))
return False;
if(!prs_uint32("SystemNameOffset", ps, depth, &block.SystemNameOffset))
return False;
/* hack to make sure we're 64-bit aligned at the end of this whole mess */
if(!prs_uint8s(False, "SystemName", ps, depth, block.data,
block.HeaderLength - block.SystemNameOffset))
return False;
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_marshall_perf_counters(prs_struct *ps,
struct PERF_OBJECT_TYPE object,
int depth)
{
int cnt;
struct PERF_COUNTER_DEFINITION counter;
prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counters");
depth++;
2009-02-14 20:49:13 +03:00
for(cnt = 0; cnt < object.NumCounters; cnt++)
{
counter = object.counters[cnt];
if(!prs_align(ps))
return False;
if(!prs_uint32("ByteLength", ps, depth, &counter.ByteLength))
return False;
if(!prs_uint32("CounterNameTitleIndex", ps, depth, &counter.CounterNameTitleIndex))
return False;
if(!prs_uint32("CounterNameTitlePointer", ps, depth, &counter.CounterNameTitlePointer))
return False;
if(!prs_uint32("CounterHelpTitleIndex", ps, depth, &counter.CounterHelpTitleIndex))
return False;
if(!prs_uint32("CounterHelpTitlePointer", ps, depth, &counter.CounterHelpTitlePointer))
return False;
if(!prs_uint32("DefaultScale", ps, depth, &counter.DefaultScale))
return False;
if(!prs_uint32("DetailLevel", ps, depth, &counter.DetailLevel))
return False;
if(!prs_uint32("CounterType", ps, depth, &counter.CounterType))
return False;
if(!prs_uint32("CounterSize", ps, depth, &counter.CounterSize))
return False;
if(!prs_uint32("CounterOffset", ps, depth, &counter.CounterOffset))
return False;
}
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_marshall_perf_counter_data(prs_struct *ps,
struct PERF_COUNTER_BLOCK counter_data,
int depth)
{
prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_counter_data");
depth++;
2009-02-14 20:49:13 +03:00
if(!prs_align_uint64(ps))
return False;
2009-02-14 20:49:13 +03:00
if(!prs_uint32("ByteLength", ps, depth, &counter_data.ByteLength))
return False;
if(!prs_uint8s(False, "CounterData", ps, depth, counter_data.data, counter_data.ByteLength - sizeof(uint32)))
return False;
if(!prs_align_uint64(ps))
return False;
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_marshall_perf_instances(prs_struct *ps,
struct PERF_OBJECT_TYPE object,
int depth)
{
struct PERF_INSTANCE_DEFINITION instance;
int inst;
prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_instances");
depth++;
for(inst = 0; inst < object.NumInstances; inst++)
{
instance = object.instances[inst];
if(!prs_align(ps))
return False;
if(!prs_uint32("ByteLength", ps, depth, &instance.ByteLength))
return False;
if(!prs_uint32("ParentObjectTitleIndex", ps, depth, &instance.ParentObjectTitleIndex))
return False;
if(!prs_uint32("ParentObjectTitlePointer", ps, depth, &instance.ParentObjectTitlePointer))
return False;
if(!prs_uint32("UniqueID", ps, depth, &instance.UniqueID))
return False;
if(!prs_uint32("NameOffset", ps, depth, &instance.NameOffset))
return False;
if(!prs_uint32("NameLength", ps, depth, &instance.NameLength))
return False;
if(!prs_uint8s(False, "InstanceName", ps, depth, instance.data,
instance.ByteLength - instance.NameOffset))
return False;
if(_reg_perfcount_marshall_perf_counter_data(ps, instance.counter_data, depth) == False)
return False;
}
2009-02-14 20:49:13 +03:00
return True;
}
/*********************************************************************
*********************************************************************/
static bool _reg_perfcount_marshall_perf_objects(prs_struct *ps, struct PERF_DATA_BLOCK block, int depth)
{
int obj;
struct PERF_OBJECT_TYPE object;
2009-02-14 20:49:13 +03:00
prs_debug(ps, depth, "", "_reg_perfcount_marshall_perf_objects");
depth++;
for(obj = 0; obj < block.NumObjectTypes; obj++)
{
object = block.objects[obj];
if(!prs_align(ps))
return False;
if(!prs_uint32("TotalByteLength", ps, depth, &object.TotalByteLength))
return False;
if(!prs_uint32("DefinitionLength", ps, depth, &object.DefinitionLength))
return False;
if(!prs_uint32("HeaderLength", ps, depth, &object.HeaderLength))
return False;
if(!prs_uint32("ObjectNameTitleIndex", ps, depth, &object.ObjectNameTitleIndex))
return False;
if(!prs_uint32("ObjectNameTitlePointer", ps, depth, &object.ObjectNameTitlePointer))
return False;
if(!prs_uint32("ObjectHelpTitleIndex", ps, depth, &object.ObjectHelpTitleIndex))
return False;
if(!prs_uint32("ObjectHelpTitlePointer", ps, depth, &object.ObjectHelpTitlePointer))
return False;
if(!prs_uint32("DetailLevel", ps, depth, &object.DetailLevel))
return False;
if(!prs_uint32("NumCounters", ps, depth, &object.NumCounters))
return False;
if(!prs_uint32("DefaultCounter", ps, depth, &object.DefaultCounter))
return False;
if(!prs_uint32("NumInstances", ps, depth, &object.NumInstances))
return False;
if(!prs_uint32("CodePage", ps, depth, &object.CodePage))
return False;
if(!prs_align_uint64(ps))
return False;
if(!prs_uint64("PerfTime", ps, depth, &object.PerfTime))
return False;
if(!prs_uint64("PerfFreq", ps, depth, &object.PerfFreq))
return False;
/* Now do the counters */
/* If no instances, encode counter_data */
/* If instances, encode instace plus counter data for each instance */
if(_reg_perfcount_marshall_perf_counters(ps, object, depth) == False)
return False;
if(object.NumInstances == PERF_NO_INSTANCES)
{
if(_reg_perfcount_marshall_perf_counter_data(ps, object.counter_data, depth) == False)
return False;
}
else
{
if(_reg_perfcount_marshall_perf_instances(ps, object, depth) == False)
return False;
}
}
return True;
}
/*********************************************************************
*********************************************************************/
WERROR reg_perfcount_get_hkpd(prs_struct *ps, uint32 max_buf_size, uint32 *outbuf_len, const char *object_ids)
{
/*
* For a detailed description of the layout of this structure,
* see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/performance_data_format.asp
*
* By 2006-11-23 this link did not work anymore, I found something
* promising under
* http://msdn2.microsoft.com/en-us/library/aa373105.aspx -- vl
*/
struct PERF_DATA_BLOCK block;
uint32 buffer_size, base_index;
2009-02-14 20:49:13 +03:00
buffer_size = 0;
base_index = reg_perfcount_get_base_index();
ZERO_STRUCT(block);
2009-10-01 12:21:17 +04:00
buffer_size = reg_perfcount_get_perf_data_block(base_index, ps->mem_ctx, &block, object_ids, ps->bigendian_data);
if(buffer_size < max_buf_size)
{
*outbuf_len = buffer_size;
2009-10-01 12:21:17 +04:00
if (!_reg_perfcount_marshall_perf_data_block(ps, block, 0))
return WERR_NOMEM;
2009-10-01 12:21:17 +04:00
if (!_reg_perfcount_marshall_perf_objects(ps, block, 0))
return WERR_NOMEM;
return WERR_OK;
}
else
{
*outbuf_len = max_buf_size;
2009-10-01 12:21:17 +04:00
if (!_reg_perfcount_marshall_perf_data_block(ps, block, 0))
return WERR_NOMEM;
return WERR_INSUFFICIENT_BUFFER;
}
}