--- samba-3.3.4/source/utils/status.c.ori 2009-05-26 11:31:05.000000000 +0200 +++ samba-3.3.4/source/utils/status.c 2009-05-26 01:20:19.000000000 +0200 @@ -45,6 +45,281 @@ static bool show_brl; static bool numeric_only; +/* begin new HPK */ + +static bool machine_readable = false; /* added by HPK */ + +#include +#include +#include + +/** class string_cache, NOT thread safe */ + +/** MUST be greater than 1 */ +#define STRING_CACHE_SIZE 500 + +#ifndef STRING_CACHE_QUOTE +#define STRING_CACHE_QUOTE '"' +#endif + +#ifndef STRING_CACHE_ESCAPE +#define STRING_CACHE_ESCAPE '\\' +#endif + +#ifndef STRING_CACHE_SEPARATOR +#define STRING_CACHE_SEPARATOR '\t' +#endif + +#ifndef STRING_CACHE_ALWAYS +#define STRING_CACHE_ALWAYS 0 +#endif + +struct string_cache_t +{ + size_t used; /**< count of used entries */ + const char* stringarray[STRING_CACHE_SIZE]; + struct string_cache_t* next; /**< will be 0 if last */ +}; + +static struct string_cache_t* string_cache_first = NULL; +static size_t string_cache_columns; +static size_t* string_cache_lens; /* array of columns count size_t's */ +static size_t string_cache_lines; + +static void string_cache_strcpy( char* dst, const char* src) +{ + while ((*dst++ = *src++) != (char)0) + ; +} + +static char* string_cache_strdup( const char* ptr) +{ + size_t len; + char* newptr; + + if (ptr == NULL) + return NULL; + len = strlen( ptr) + 1; + if (len == 0) + return NULL; /* integer overflow */ + newptr = malloc( len); + if (newptr) + string_cache_strcpy( newptr, ptr); + return newptr; +} + +static const char* string_cache_strquote( const char* ptr) +{ + size_t len; + size_t adjust = 0; + char* newptr; + const char* tmp; + char* dst; + const char* last; + static char stop[] = + { + '\n', + STRING_CACHE_QUOTE, + STRING_CACHE_ESCAPE, + STRING_CACHE_SEPARATOR, + (char)0 /* end */ + }; + + if (ptr == NULL) + return NULL; + len = strlen( ptr) + 1; + if (len == 0) + return NULL; /* integer overflow */ + + /* check if quoting is necessary, not the minimal check but easy */ + for (tmp = ptr; (tmp = strpbrk( tmp, stop)) != NULL; ++tmp) + ++adjust; + +#if STRING_CACHE_ALWAYS + if (adjust == 0) + return string_cache_strdup( ptr); /* nothing todo */ +#endif /* #if STRING_CACHE_ALWAYS */ + + if (adjust + 2 < adjust) + return NULL; /* integer overflow */ + adjust += 2; /* leading and trailing quote */ + + if (len + adjust < len) + return NULL; /* integer overflow */ + newptr = malloc( len + adjust); + if (newptr) + { + *newptr = STRING_CACHE_QUOTE; /* start new string with quote */ + for (tmp = ptr, dst = newptr+1, last = ptr; (tmp = strpbrk( tmp, stop)) != NULL;) + { + strncpy( dst, last, tmp-last); /* copy the normal characters */ + dst += tmp-last; + *dst++ = STRING_CACHE_ESCAPE; + *dst++ = *tmp++; + last = tmp; + } + string_cache_strcpy( dst, last); + dst += strlen( dst); + *dst++ = STRING_CACHE_QUOTE; + *dst = (char)0; + } + return newptr; +} + + +/** deletes the structures from string_cache_first */ +static void string_cache_delete() +{ + struct string_cache_t* curr = string_cache_first; + struct string_cache_t* tmp; + string_cache_first = NULL; + while (curr) + { + while (curr->used--) + free( (void*)curr->stringarray[curr->used]); /* was allocated via string_cache_strdup */ + tmp = curr->next; + free( curr); + curr = tmp; + } + free( string_cache_lens); + string_cache_lens = NULL; + string_cache_lines = 0; /* no data at this moment */ +} + + +static void string_cache_add( size_t cols, const char* textarray[]) +{ + /* textarray MUST have string_cache_columns items, but how to check if not C++ ??? */ + assert( textarray != NULL); + + /* cols MUST be equal to string_cache_columns */ + assert( cols == string_cache_columns); + + /* string_cache_first MUST be allocated */ + assert( string_cache_first != NULL); + + /* find first unused entry */ + size_t len; + struct string_cache_t* curr = string_cache_first; + while (curr->used == STRING_CACHE_SIZE) /* a new struct will be allocated if the struct is fully used, even if the next struct will NOT be used */ + curr = curr->next; + + /* add items */ + while (cols--) { + if (*textarray) + { /* only if text, the items may be NULL */ + len = strlen( *textarray); + if (string_cache_lens[string_cache_columns-(1+cols)] < len) + string_cache_lens[string_cache_columns-(1+cols)] = len; /* remember the longest string for this col */ + } + curr->stringarray[curr->used++] = machine_readable ? string_cache_strquote( *textarray) : string_cache_strdup( *textarray); /* save a copy or NULL */ + ++textarray; /* it's clearer here and not in ?: */ + + /* check if there must be a new struct allocated */ + if (curr->used >= STRING_CACHE_SIZE) + { + curr->next = (struct string_cache_t*)calloc( 1, sizeof( struct string_cache_t)); /* may be NULL */ + curr = curr->next; + /* if curr is NULL (because of no memory), than end */ + if (!curr) + return; + } + } +} + +static void string_cache_heading( size_t cols, const char* textarray[]) +{ + /* textarray MUST have string_cache_columns items, but how to check if not C++ ??? */ + assert( textarray != NULL); + + /* cols MUST be greater than 0 */ + assert( cols > 0); + + string_cache_delete(); /* starts a new use case, NOT thread safe */ + string_cache_columns = cols; /* remember for later use */ + string_cache_lens = (size_t*)calloc( cols, sizeof( size_t)); /* all lens are 0 */ + string_cache_first = (struct string_cache_t*)calloc( 1, sizeof( struct string_cache_t)); /* all elements are 0 */ + string_cache_add( cols, textarray); +} + +static void string_cache_line( size_t cols, const char* textarray[]) +{ + /* textarray MUST have string_cache_columns items, but how to check if not C++ ??? */ + assert( textarray != NULL); + + /* cols MUST be equal to string_cache_columns */ + assert( cols == string_cache_columns); + + string_cache_add( string_cache_columns, textarray); + ++string_cache_lines; +} + +static void string_cache_print( const char* begintext, const char* endtext, bool print_if_empty) +{ + size_t line, col, nr = 0, len = string_cache_columns-1; + struct string_cache_t* curr = string_cache_first; + const char* tmp; + const char* sep; + if (machine_readable) + print_if_empty = false; /* never print empty things if machine readable */ + if (curr == NULL || (!print_if_empty && string_cache_lines == 0)) + { + string_cache_delete(); + return; /* do nothing if nothing to print */ + } + if (!begintext) + begintext = ""; + d_printf( "\n%s", begintext); + if (*begintext) /* not empty */ + d_printf( "\n"); + for (line = 0; line <= string_cache_lines; ++line) /* one more for heading */ + { + sep = ""; + for (col = 0; col < string_cache_columns; ++col) + { + /* check if next struct */ + if (nr == curr->used) + { + nr = 0; + curr = curr->next; + } + tmp = curr->stringarray[nr++]; + if (!tmp) + tmp = ""; /* empty string if NULL */ + if (machine_readable) + { + /* print with quote and separator, all string are quoted */ + if (col) + d_printf( "%c", STRING_CACHE_SEPARATOR); + d_printf( "%s", tmp); + } + else + { + /* print formatted */ + d_printf( "%s%-*s", sep, string_cache_lens[col], tmp); + sep = " "; + } + } + d_printf( "\n"); + if (!machine_readable && line == 0) /* ruler */ + { + for (col = 0; col < string_cache_columns; ++col) + len += string_cache_lens[col]; + while (len--) + d_printf( "-"); + d_printf( "\n"); + } + } + if (!endtext) + endtext = ""; + d_printf( "%s", endtext); + + string_cache_delete(); /* ends this use case, NOT thread safe */ +} + +/* end new HPK */ + + const char *username = NULL; extern bool status_profile_dump(bool be_verbose); @@ -105,8 +380,11 @@ const char *fname, void *dummy) { - static int count; - + const char* textarray[9]; + char* tmp; + size_t len, cnt = 0; + fstring uid_str, acc_str, err_str; + if (!is_valid_share_mode_entry(e)) { return; } @@ -115,58 +393,98 @@ return; } - if (count==0) { - d_printf("Locked files:\n"); - d_printf("Pid Uid DenyMode Access R/W Oplock SharePath Name Time\n"); - d_printf("--------------------------------------------------------------------------------------------------\n"); - } - count++; - - if (Ucrit_checkPid(e->pid)) { - d_printf("%-11s ",procid_str_static(&e->pid)); - d_printf("%-9u ", (unsigned int)e->uid); - switch (map_share_mode_to_deny_mode(e->share_access, - e->private_options)) { - case DENY_NONE: d_printf("DENY_NONE "); break; - case DENY_ALL: d_printf("DENY_ALL "); break; - case DENY_DOS: d_printf("DENY_DOS "); break; - case DENY_READ: d_printf("DENY_READ "); break; - case DENY_WRITE:printf("DENY_WRITE "); break; - case DENY_FCB: d_printf("DENY_FCB "); break; - default: { - d_printf("unknown-please report ! " - "e->share_access = 0x%x, " - "e->private_options = 0x%x\n", - (unsigned int)e->share_access, - (unsigned int)e->private_options ); - break; - } - } - d_printf("0x%-8x ",(unsigned int)e->access_mask); - if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))== - (FILE_READ_DATA|FILE_WRITE_DATA)) { - d_printf("RDWR "); - } else if (e->access_mask & FILE_WRITE_DATA) { - d_printf("WRONLY "); - } else { - d_printf("RDONLY "); - } + if (!Ucrit_checkPid(e->pid)) { + return; + } - if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == - (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) { - d_printf("EXCLUSIVE+BATCH "); - } else if (e->op_type & EXCLUSIVE_OPLOCK) { - d_printf("EXCLUSIVE "); - } else if (e->op_type & BATCH_OPLOCK) { - d_printf("BATCH "); - } else if (e->op_type & LEVEL_II_OPLOCK) { - d_printf("LEVEL_II "); - } else { - d_printf("NONE "); + /* PID */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( procid_str_static(&e->pid)); + + /* UID */ + fstr_sprintf( uid_str, "%u", (unsigned int)e->uid); + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( uid_str); + + /* DenyMode */ + switch (map_share_mode_to_deny_mode(e->share_access, + e->private_options)) { + case DENY_NONE: tmp = "DENY_NONE"; break; + case DENY_ALL: tmp = "DENY_ALL"; break; + case DENY_DOS: tmp = "DENY_DOS"; break; + case DENY_READ: tmp = "DENY_READ"; break; + case DENY_WRITE: tmp = "DENY_WRITE"; break; + case DENY_FCB: tmp = "DENY_FCB"; break; + default: { + fstr_sprintf( err_str, "unknown-please report ! " + "e->share_access = 0x%x, " + "e->private_options = 0x%x\n", + (unsigned int)e->share_access, + (unsigned int)e->private_options ); + tmp = err_str; + break; } - - d_printf(" %s %s %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec)); } + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( tmp); + + + /* Access */ + fstr_sprintf( acc_str, "0x%-8x ",(unsigned int)e->access_mask); + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( acc_str); + + + /* R/W */ + if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))== + (FILE_READ_DATA|FILE_WRITE_DATA)) { + tmp = "RDWR"; + } else if (e->access_mask & FILE_WRITE_DATA) { + tmp = "WRONLY"; + } else { + tmp = "RDONLY"; + } + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( tmp); + + /* Oplock */ + if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == + (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) { + tmp = "EXCLUSIVE+BATCH"; + } else if (e->op_type & EXCLUSIVE_OPLOCK) { + tmp = "EXCLUSIVE"; + } else if (e->op_type & BATCH_OPLOCK) { + tmp = "BATCH"; + } else if (e->op_type & LEVEL_II_OPLOCK) { + tmp = "LEVEL_II"; + } else { + tmp = "NONE"; + } + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( tmp); + + /* SharePath */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( sharepath); + + /* Name */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( fname); + + /* Time */ + tmp = string_cache_strdup( time_to_asc((time_t)e->time.tv_sec)); /* time_to_asc makes NL at end */ + len = strlen( tmp); + if (len-- > 0) + tmp[len] = (char)0; + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = tmp; + + /* cache line */ + string_cache_line( cnt, textarray); + + /* free used memory */ + while (cnt--) + free( (void*)textarray[cnt]); } static void print_brl(struct file_id id, @@ -177,8 +495,10 @@ br_off size, void *private_data) { - static int count; + const char* textarray[7]; + size_t cnt = 0; int i; + fstring start_str, size_str; static const struct { enum brl_type lock_type; const char *desc; @@ -194,30 +514,53 @@ const char *fname = ""; struct share_mode_lock *share_mode; - if (count==0) { - d_printf("Byte range locks:\n"); - d_printf("Pid dev:inode R/W start size SharePath Name\n"); - d_printf("--------------------------------------------------------------------------------\n"); - } - count++; - share_mode = fetch_share_mode_unlocked(NULL, id, "__unspecified__", "__unspecified__"); if (share_mode) { sharepath = share_mode->servicepath; fname = share_mode->filename; } + /* PID */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( procid_str_static(&pid)); + + /* dev:inode */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( file_id_string_tos(&id)); + + /* R/W */ for (i=0;icnum == -1) return 0; @@ -234,10 +581,32 @@ return 0; } - d_printf("%-10s %s %-12s %s", - crec->servicename,procid_str_static(&crec->pid), - crec->machine, - time_to_asc(crec->start)); + /* Service */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( crec->servicename); + + /* PID */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( procid_str_static(&crec->pid)); + + /* Machine */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( crec->machine); + + /* Connected at */ + tmp = string_cache_strdup( time_to_asc(crec->start)); /* time_to_asc makes NL at end */ + len = strlen( tmp); + if (len-- > 0) + tmp[len] = (char)0; + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = tmp; + + /* cache line */ + string_cache_line( cnt, textarray); + + /* free used memory */ + while (cnt--) + free( (void*)textarray[cnt]); return 0; } @@ -246,6 +615,8 @@ { struct sessionid sessionid; fstring uid_str, gid_str; + const char* textarray[5]; + size_t cnt = 0; if (db->value.dsize != sizeof(sessionid)) return 0; @@ -258,14 +629,33 @@ Ucrit_addPid( sessionid.pid ); + /* prepare only */ fstr_sprintf(uid_str, "%d", sessionid.uid); fstr_sprintf(gid_str, "%d", sessionid.gid); - d_printf("%-7s %-12s %-12s %-12s (%s)\n", - procid_str_static(&sessionid.pid), - numeric_only ? uid_str : uidtoname(sessionid.uid), - numeric_only ? gid_str : gidtoname(sessionid.gid), - sessionid.remote_machine, sessionid.hostname); + /* PID */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( procid_str_static(&sessionid.pid)); + + /* user */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( numeric_only ? uid_str : uidtoname(sessionid.uid)); + + /* group */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( numeric_only ? gid_str : gidtoname(sessionid.gid)); + + /* machine */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( sessionid.remote_machine); + + /* machine-name/IP */ + assert( cnt < ARRAY_SIZE( textarray)); + textarray[cnt++] = string_cache_strdup( sessionid.hostname); + + string_cache_line( cnt, textarray); + while (cnt--) + free( (void*)textarray[cnt]); return 0; } @@ -291,6 +681,7 @@ {"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" }, {"byterange", 'B', POPT_ARG_NONE, NULL, 'B', "Include byte range locks"}, {"numeric", 'n', POPT_ARG_NONE, NULL, 'n', "Numeric uid/gid"}, + {"machine-readable", 'm', POPT_ARG_NONE, NULL, 'm', "Format output machine readable"}, /* added by HPK */ POPT_COMMON_SAMBA POPT_TABLEEND }; @@ -298,6 +689,11 @@ int ret = 0; struct messaging_context *msg_ctx; + static const char* heading_shares[] = { "Service", "pid", "machine", "Connected at" }; + static const char* heading_processes[] = { "PID", "Username", "Group", "Machine", "M-Name/IP" }; + static const char* heading_locks[] = { "Pid", "Uid", "DenyMode", "Access", "R/W", "Oplock", "SharePath", "Name", "Time" }; + static const char* heading_brl[] = { "Pid", "dev:inode", "R/W", "start", "size", "SharePath", "Name" }; + sec_init(); load_case_tables(); @@ -316,6 +712,9 @@ while ((c = poptGetNextOpt(pc)) != -1) { switch (c) { + case 'm': /* added by HPK */ + machine_readable = true; + break; case 'p': processes_only = true; break; @@ -406,11 +805,14 @@ if (!db) { d_printf("sessionid.tdb not initialised\n"); } else { - d_printf("\nSamba version %s\n",SAMBA_VERSION_STRING); - d_printf("PID Username Group Machine \n"); - d_printf("-------------------------------------------------------------------\n"); + if (!machine_readable) + d_printf("\nSamba version %s",SAMBA_VERSION_STRING); + + string_cache_heading( ARRAY_SIZE( heading_processes), heading_processes); db->traverse_read(db, traverse_sessionid, NULL); + string_cache_print( "Processes:", "", true); + TALLOC_FREE(db); } @@ -427,13 +829,12 @@ if (brief) { goto done; } - - d_printf("\nService pid machine Connected at\n"); - d_printf("-------------------------------------------------------\n"); - + + string_cache_heading( ARRAY_SIZE( heading_shares), heading_shares); + connections_forall(traverse_fn1, NULL); - d_printf("\n"); + string_cache_print( "Shares:", "", true); if ( shares_only ) { goto done; @@ -462,18 +863,21 @@ goto done; } + string_cache_heading( ARRAY_SIZE( heading_locks), heading_locks); result = share_mode_forall(print_share_mode, NULL); + string_cache_print( "Locked files:", "", false); if (result == 0) { - d_printf("No locked files\n"); + if (!machine_readable) + d_printf("\nNo locked files\n"); } else if (result == -1) { d_printf("locked file list truncated\n"); } - d_printf("\n"); - if (show_brl) { + string_cache_heading( ARRAY_SIZE( heading_brl), heading_brl); brl_forall(print_brl, NULL); + string_cache_print( "Byte range locks:", "", false); } locking_end();