2002-02-02 04:17:29 +05:30
|
|
|
/*
|
2002-12-15 06:00:17 +05:30
|
|
|
* Copyright 1998-2002 by Albert Cahalan; all rights resered.
|
2002-02-02 04:17:29 +05:30
|
|
|
* This file may be used subject to the terms and conditions of the
|
|
|
|
* GNU Library General Public License Version 2, or any later version
|
|
|
|
* at your option, as published by the Free Software Foundation.
|
|
|
|
* 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 Library General Public License for more details.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
#include <sys/sysmacros.h>
|
2002-12-09 12:30:07 +05:30
|
|
|
#include "../proc/wchan.h"
|
2002-02-02 04:17:29 +05:30
|
|
|
#include "../proc/version.h"
|
|
|
|
#include "../proc/sysinfo.h"
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __GNU_LIBRARY__
|
|
|
|
#define __GNU_LIBRARY__ -1
|
|
|
|
#endif
|
|
|
|
#ifndef __GLIBC__
|
|
|
|
#define __GLIBC__ -1
|
|
|
|
#endif
|
|
|
|
#ifndef __GLIBC_MINOR__
|
|
|
|
#define __GLIBC_MINOR__ -1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2002-10-12 09:55:57 +05:30
|
|
|
static const char * saved_personality_text = "You found a bug!";
|
2002-02-02 04:17:29 +05:30
|
|
|
|
|
|
|
int all_processes = -1;
|
2002-10-12 09:55:57 +05:30
|
|
|
const char *bsd_j_format = (const char *)0xdeadbeef;
|
|
|
|
const char *bsd_l_format = (const char *)0xdeadbeef;
|
|
|
|
const char *bsd_s_format = (const char *)0xdeadbeef;
|
|
|
|
const char *bsd_u_format = (const char *)0xdeadbeef;
|
|
|
|
const char *bsd_v_format = (const char *)0xdeadbeef;
|
2002-02-02 04:17:29 +05:30
|
|
|
int bsd_c_option = -1;
|
|
|
|
int bsd_e_option = -1;
|
|
|
|
uid_t cached_euid = -1;
|
|
|
|
dev_t cached_tty = -1;
|
2002-11-27 05:54:01 +05:30
|
|
|
char forest_prefix[4 * 32*1024 + 100]; // FIXME
|
2002-02-02 04:17:29 +05:30
|
|
|
int forest_type = -1;
|
|
|
|
unsigned format_flags = 0xffffffff; /* -l -f l u s -j... */
|
|
|
|
format_node *format_list = (format_node *)0xdeadbeef; /* digested formatting options */
|
|
|
|
unsigned format_modifiers = 0xffffffff; /* -c -j -y -P -L... */
|
|
|
|
int header_gap = -1;
|
|
|
|
int header_type = -1;
|
|
|
|
int include_dead_children = -1;
|
|
|
|
int lines_to_next_header = -1;
|
|
|
|
const char *namelist_file = (const char *)0xdeadbeef;
|
|
|
|
int negate_selection = -1;
|
|
|
|
int running_only = -1;
|
2002-11-27 05:54:01 +05:30
|
|
|
int page_size = -1; // "int" for math reasons?
|
2002-02-02 04:17:29 +05:30
|
|
|
unsigned personality = 0xffffffff;
|
|
|
|
int prefer_bsd_defaults = -1;
|
|
|
|
int screen_cols = -1;
|
|
|
|
int screen_rows = -1;
|
|
|
|
unsigned long seconds_since_boot = -1;
|
|
|
|
selection_node *selection_list = (selection_node *)0xdeadbeef;
|
|
|
|
unsigned simple_select = 0xffffffff;
|
|
|
|
sort_node *sort_list = (sort_node *)0xdeadbeef; /* ready-to-use sort list */
|
2002-10-12 09:55:57 +05:30
|
|
|
const char *sysv_f_format = (const char *)0xdeadbeef;
|
|
|
|
const char *sysv_fl_format = (const char *)0xdeadbeef;
|
|
|
|
const char *sysv_j_format = (const char *)0xdeadbeef;
|
|
|
|
const char *sysv_l_format = (const char *)0xdeadbeef;
|
2003-09-20 13:59:55 +05:30
|
|
|
unsigned thread_flags = 0xffffffff;
|
2002-02-02 04:17:29 +05:30
|
|
|
int unix_f_option = -1;
|
|
|
|
int user_is_number = -1;
|
|
|
|
int wchan_is_number = -1;
|
|
|
|
|
|
|
|
|
|
|
|
static void reset_selection_list(void){
|
|
|
|
selection_node *old;
|
|
|
|
selection_node *walk = selection_list;
|
|
|
|
if(selection_list == (selection_node *)0xdeadbeef){
|
|
|
|
selection_list = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while(walk){
|
|
|
|
old = walk;
|
|
|
|
walk = old->next;
|
|
|
|
free(old->u);
|
|
|
|
free(old);
|
|
|
|
}
|
|
|
|
selection_list = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The rules:
|
|
|
|
* 1. Defaults are implementation-specific. (ioctl,termcap,guess)
|
|
|
|
* 2. COLUMNS and LINES override the defaults. (standards compliance)
|
|
|
|
* 3. Command line options override everything else.
|
|
|
|
* 4. Actual output may be more if the above is too narrow.
|
|
|
|
*/
|
|
|
|
static void set_screen_size(void){
|
|
|
|
struct winsize ws;
|
|
|
|
char *columns; /* Unix98 environment variable */
|
|
|
|
char *lines; /* Unix98 environment variable */
|
|
|
|
if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0){
|
|
|
|
screen_cols = ws.ws_col;
|
|
|
|
screen_rows = ws.ws_row;
|
|
|
|
}else{ /* TODO: ought to do tgetnum("co") and tgetnum("li") now */
|
|
|
|
screen_cols = 80;
|
|
|
|
screen_rows = 24;
|
|
|
|
}
|
|
|
|
if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
|
|
|
|
columns = getenv("COLUMNS");
|
|
|
|
if(columns && *columns){
|
|
|
|
long t;
|
|
|
|
char *endptr;
|
|
|
|
t = strtol(columns, &endptr, 0);
|
|
|
|
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
|
|
|
|
}
|
|
|
|
lines = getenv("LINES");
|
|
|
|
if(lines && *lines){
|
|
|
|
long t;
|
|
|
|
char *endptr;
|
|
|
|
t = strtol(lines, &endptr, 0);
|
|
|
|
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
|
|
|
|
}
|
|
|
|
if((screen_cols<9) || (screen_rows<2))
|
|
|
|
fprintf(stderr,"Your %dx%d screen size is bogus. Expect trouble.\n",
|
|
|
|
screen_cols, screen_rows
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************** personality control **************/
|
|
|
|
|
|
|
|
typedef struct personality_table_struct {
|
|
|
|
const char *name; /* personality name */
|
|
|
|
const void *jump; /* See gcc extension info. :-) */
|
|
|
|
} personality_table_struct;
|
|
|
|
|
|
|
|
static int compare_personality_table_structs(const void *a, const void *b){
|
2002-10-12 09:55:57 +05:30
|
|
|
return strcasecmp(((const personality_table_struct*)a)->name,((const personality_table_struct*)b)->name);
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static const char *set_personality(void){
|
2002-10-12 09:55:57 +05:30
|
|
|
const char *s;
|
2002-02-02 04:17:29 +05:30
|
|
|
size_t sl;
|
|
|
|
char buf[16];
|
|
|
|
personality_table_struct findme = { buf, NULL};
|
|
|
|
personality_table_struct *found;
|
|
|
|
static const personality_table_struct personality_table[] = {
|
|
|
|
{"390", &&case_390},
|
|
|
|
{"aix", &&case_aix},
|
|
|
|
{"bsd", &&case_bsd},
|
|
|
|
{"compaq", &&case_compaq},
|
|
|
|
{"debian", &&case_debian},
|
|
|
|
{"default", &&case_default},
|
|
|
|
{"digital", &&case_digital},
|
|
|
|
{"gnu", &&case_gnu},
|
|
|
|
{"hp", &&case_hp},
|
|
|
|
{"hpux", &&case_hpux},
|
|
|
|
{"irix", &&case_irix},
|
|
|
|
{"linux", &&case_linux},
|
|
|
|
{"old", &&case_old},
|
|
|
|
{"os390", &&case_os390},
|
|
|
|
{"posix", &&case_posix},
|
|
|
|
{"s390", &&case_s390},
|
|
|
|
{"sco", &&case_sco},
|
|
|
|
{"sgi", &&case_sgi},
|
|
|
|
{"solaris2", &&case_solaris2},
|
|
|
|
{"sunos4", &&case_sunos4},
|
|
|
|
{"sysv", &&case_sysv},
|
|
|
|
{"tru64", &&case_tru64},
|
|
|
|
{"unix", &&case_unix},
|
|
|
|
{"unix95", &&case_unix95},
|
|
|
|
{"unix98", &&case_unix98},
|
|
|
|
{"unknown", &&case_unknown}
|
|
|
|
};
|
|
|
|
const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
|
|
|
|
|
|
|
|
personality = 0;
|
|
|
|
prefer_bsd_defaults = 0;
|
|
|
|
|
|
|
|
bsd_j_format = "OL_j";
|
|
|
|
bsd_l_format = "OL_l";
|
|
|
|
bsd_s_format = "OL_s";
|
|
|
|
bsd_u_format = "OL_u";
|
|
|
|
bsd_v_format = "OL_v";
|
|
|
|
|
|
|
|
/* When these are NULL, the code does SysV output modifier logic */
|
|
|
|
sysv_f_format = NULL;
|
|
|
|
sysv_fl_format = NULL;
|
|
|
|
sysv_j_format = NULL;
|
|
|
|
sysv_l_format = NULL;
|
|
|
|
|
|
|
|
s = getenv("PS_PERSONALITY");
|
|
|
|
if(!s || !*s) s = getenv("CMD_ENV");
|
|
|
|
if(!s || !*s) s="unknown"; /* "Do The Right Thing[tm]" */
|
|
|
|
if(getenv("I_WANT_A_BROKEN_PS")) s="old";
|
|
|
|
sl = strlen(s);
|
|
|
|
if(sl > 15) return "Environment specified an unknown personality.";
|
|
|
|
strncpy(buf, s, sl);
|
|
|
|
buf[sl] = '\0';
|
|
|
|
saved_personality_text = strdup(buf);
|
|
|
|
|
|
|
|
found = bsearch(&findme, personality_table, personality_table_count,
|
|
|
|
sizeof(personality_table_struct), compare_personality_table_structs
|
|
|
|
);
|
|
|
|
|
|
|
|
if(!found) return "Environment specified an unknown personality.";
|
|
|
|
|
|
|
|
goto *(found->jump); /* See gcc extension info. :-) */
|
|
|
|
|
|
|
|
case_bsd:
|
|
|
|
personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
|
|
|
|
prefer_bsd_defaults = 1;
|
|
|
|
bsd_j_format = "FB_j";
|
|
|
|
bsd_l_format = "FB_l";
|
|
|
|
/* bsd_s_format not used */
|
|
|
|
bsd_u_format = "FB_u";
|
|
|
|
bsd_v_format = "FB_v";
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_old:
|
|
|
|
personality = PER_FORCE_BSD | PER_OLD_m;
|
|
|
|
prefer_bsd_defaults = 1;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_debian: /* Toss this? They don't seem to care much. */
|
|
|
|
case_gnu:
|
|
|
|
personality = PER_GOOD_o | PER_CUMUL_MARKED | PER_OLD_m;
|
|
|
|
prefer_bsd_defaults = 1;
|
|
|
|
sysv_f_format = "RD_f";
|
|
|
|
/* sysv_fl_format = "RD_fl"; */ /* Debian can't do this! */
|
|
|
|
sysv_j_format = "RD_j";
|
|
|
|
sysv_l_format = "RD_l";
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_linux:
|
|
|
|
personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_default: /* use defaults for ps, ignoring other environment variables */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_unknown: /* defaults, but also check inferior environment variables */
|
|
|
|
if(
|
|
|
|
getenv("UNIX95") /* Irix */
|
|
|
|
|| getenv("POSIXLY_CORRECT") /* most gnu stuff */
|
|
|
|
|| (getenv("POSIX2") && !strcmp(getenv("POSIX2"), "on")) /* Unixware 7 */
|
|
|
|
) personality = PER_BROKEN_o;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_aix:
|
|
|
|
bsd_j_format = "FB_j";
|
|
|
|
bsd_l_format = "FB_l";
|
|
|
|
/* bsd_s_format not used */
|
|
|
|
bsd_u_format = "FB_u";
|
|
|
|
bsd_v_format = "FB_v";
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_tru64:
|
|
|
|
case_compaq:
|
|
|
|
case_digital:
|
|
|
|
personality = PER_GOOD_o | PER_BSD_h;
|
|
|
|
prefer_bsd_defaults = 1;
|
|
|
|
sysv_f_format = "F5FMT";
|
|
|
|
sysv_fl_format = "FL5FMT";
|
|
|
|
sysv_j_format = "JFMT";
|
|
|
|
sysv_l_format = "L5FMT";
|
|
|
|
bsd_j_format = "JFMT";
|
|
|
|
bsd_l_format = "LFMT";
|
|
|
|
bsd_s_format = "SFMT";
|
|
|
|
bsd_u_format = "UFMT";
|
|
|
|
bsd_v_format = "VFMT";
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_sunos4:
|
|
|
|
personality = PER_NO_DEFAULT_g;
|
|
|
|
prefer_bsd_defaults = 1;
|
|
|
|
bsd_j_format = "FB_j";
|
|
|
|
bsd_l_format = "FB_l";
|
|
|
|
/* bsd_s_format not used */
|
|
|
|
bsd_u_format = "FB_u";
|
|
|
|
bsd_v_format = "FB_v";
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_irix:
|
|
|
|
case_sgi:
|
|
|
|
s = getenv("_XPG");
|
|
|
|
if(s && s[0]>'0' && s[0]<='9') personality = PER_BROKEN_o;
|
|
|
|
else personality = PER_IRIX_l;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_os390: /* IBM's OS/390 OpenEdition on the S/390 mainframe */
|
|
|
|
case_s390:
|
|
|
|
case_390:
|
|
|
|
sysv_j_format = "J390"; /* don't know what -jl and -jf do */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case_hp:
|
|
|
|
case_hpux:
|
|
|
|
case_posix:
|
|
|
|
case_sco:
|
|
|
|
case_solaris2:
|
|
|
|
case_sysv:
|
|
|
|
case_unix95:
|
|
|
|
case_unix98:
|
|
|
|
case_unix:
|
|
|
|
personality = PER_BROKEN_o;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************ Call this to reinitialize everything ***************/
|
|
|
|
void reset_global(void){
|
|
|
|
static proc_t p;
|
|
|
|
reset_selection_list();
|
|
|
|
look_up_our_self(&p);
|
|
|
|
set_screen_size();
|
|
|
|
set_personality();
|
|
|
|
|
|
|
|
all_processes = 0;
|
|
|
|
bsd_c_option = 0;
|
|
|
|
bsd_e_option = 0;
|
|
|
|
cached_euid = geteuid();
|
|
|
|
cached_tty = p.tty;
|
|
|
|
/* forest_prefix must be all zero because of POSIX */
|
|
|
|
forest_type = 0;
|
|
|
|
format_flags = 0; /* -l -f l u s -j... */
|
|
|
|
format_list = NULL; /* digested formatting options */
|
|
|
|
format_modifiers = 0; /* -c -j -y -P -L... */
|
|
|
|
header_gap = -1; /* send lines_to_next_header to -infinity */
|
|
|
|
header_type = HEAD_SINGLE;
|
|
|
|
include_dead_children = 0;
|
|
|
|
lines_to_next_header = 1;
|
|
|
|
namelist_file = NULL;
|
|
|
|
negate_selection = 0;
|
2002-11-27 05:54:01 +05:30
|
|
|
page_size = getpagesize();
|
2002-02-02 04:17:29 +05:30
|
|
|
running_only = 0;
|
|
|
|
seconds_since_boot = uptime(0,0);
|
|
|
|
selection_list = NULL;
|
|
|
|
simple_select = 0;
|
|
|
|
sort_list = NULL;
|
2003-09-20 13:59:55 +05:30
|
|
|
thread_flags = 0;
|
2002-02-02 04:17:29 +05:30
|
|
|
unix_f_option = 0;
|
|
|
|
user_is_number = 0;
|
|
|
|
wchan_is_number = 0;
|
|
|
|
}
|
|
|
|
|
2003-01-22 14:01:50 +05:30
|
|
|
static const char archdefs[] =
|
|
|
|
#ifdef __alpha__
|
|
|
|
" alpha"
|
|
|
|
#endif
|
|
|
|
#ifdef __arm__
|
|
|
|
" arm"
|
|
|
|
#endif
|
|
|
|
#ifdef __hppa__
|
|
|
|
" hppa"
|
|
|
|
#endif
|
|
|
|
#ifdef __i386__
|
|
|
|
" i386"
|
|
|
|
#endif
|
|
|
|
#ifdef __ia64__
|
|
|
|
" ia64"
|
|
|
|
#endif
|
|
|
|
#ifdef __mc68000__
|
|
|
|
" mc68000"
|
|
|
|
#endif
|
|
|
|
#ifdef __mips64__
|
|
|
|
" mips64"
|
|
|
|
#endif
|
|
|
|
#ifdef __mips__
|
|
|
|
" mips"
|
|
|
|
#endif
|
|
|
|
#ifdef __powerpc__
|
|
|
|
" powerpc"
|
|
|
|
#endif
|
|
|
|
#ifdef __sh3__
|
|
|
|
" sh3"
|
|
|
|
#endif
|
|
|
|
#ifdef __sh__
|
|
|
|
" sh"
|
|
|
|
#endif
|
|
|
|
#ifdef __sparc__
|
|
|
|
" sparc"
|
|
|
|
#endif
|
|
|
|
#ifdef __sparc_v9__
|
|
|
|
" sparc_v9"
|
|
|
|
#endif
|
|
|
|
#ifdef __x86_64__
|
|
|
|
" x86_64"
|
|
|
|
#endif
|
|
|
|
"";
|
|
|
|
|
2002-02-02 04:17:29 +05:30
|
|
|
/*********** spew variables ***********/
|
|
|
|
void self_info(void){
|
|
|
|
fprintf(stderr,
|
|
|
|
"BSD j %s\n"
|
|
|
|
"BSD l %s\n"
|
|
|
|
"BSD s %s\n"
|
|
|
|
"BSD u %s\n"
|
|
|
|
"BSD v %s\n"
|
|
|
|
"SysV -f %s\n"
|
|
|
|
"SysV -fl %s\n"
|
|
|
|
"SysV -j %s\n"
|
|
|
|
"SysV -l %s\n"
|
|
|
|
"\n",
|
|
|
|
bsd_j_format ? bsd_j_format : "(none)",
|
|
|
|
bsd_l_format ? bsd_l_format : "(none)",
|
|
|
|
bsd_s_format ? bsd_s_format : "(none)",
|
|
|
|
bsd_u_format ? bsd_u_format : "(none)",
|
|
|
|
bsd_v_format ? bsd_v_format : "(none)",
|
|
|
|
sysv_f_format ? sysv_f_format : "(none)",
|
|
|
|
sysv_fl_format ? sysv_fl_format : "(none)",
|
|
|
|
sysv_j_format ? sysv_j_format : "(none)",
|
|
|
|
sysv_l_format ? sysv_l_format : "(none)"
|
|
|
|
);
|
|
|
|
|
|
|
|
display_version();
|
|
|
|
fprintf(stderr, "Linux version %d.%d.%d\n",
|
|
|
|
LINUX_VERSION_MAJOR(linux_version_code),
|
|
|
|
LINUX_VERSION_MINOR(linux_version_code),
|
|
|
|
LINUX_VERSION_PATCH(linux_version_code)
|
|
|
|
);
|
|
|
|
/* __libc_print_version(); */ /* how can we get the run-time version? */
|
2003-01-22 14:01:50 +05:30
|
|
|
fprintf(stderr, "Compiled with: glibc %d.%d, gcc %d.%d\n\n",
|
|
|
|
__GLIBC__, __GLIBC_MINOR__, __GNUC__, __GNUC_MINOR__
|
2002-02-02 04:17:29 +05:30
|
|
|
);
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
"header_gap=%d lines_to_next_header=%d\n"
|
|
|
|
"screen_cols=%d screen_rows=%d\n"
|
|
|
|
"\n",
|
|
|
|
header_gap, lines_to_next_header,
|
|
|
|
screen_cols, screen_rows
|
|
|
|
);
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
"personality=0x%08x (from \"%s\")\n"
|
2002-11-27 05:54:01 +05:30
|
|
|
"EUID=%d TTY=%d,%d Hertz=%Ld PAGE_SIZE=%d page_size=%d\n",
|
2002-02-02 04:17:29 +05:30
|
|
|
personality, saved_personality_text,
|
2002-11-27 05:54:01 +05:30
|
|
|
cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz,
|
|
|
|
(int)(PAGE_SIZE), (int)(page_size)
|
2002-02-02 04:17:29 +05:30
|
|
|
);
|
2002-11-27 05:54:01 +05:30
|
|
|
|
2003-01-22 14:01:50 +05:30
|
|
|
fprintf(stderr,
|
|
|
|
"sizeof(proc_t)=%d sizeof(long)=%d sizeof(KLONG)=%d\n",
|
|
|
|
(int)sizeof(proc_t), (int)sizeof(long), (int)sizeof(KLONG)
|
|
|
|
);
|
|
|
|
|
|
|
|
fprintf(stderr, "archdefs:%s\n", archdefs);
|
|
|
|
|
2002-11-27 05:54:01 +05:30
|
|
|
open_psdb(namelist_file);
|
|
|
|
fprintf(stderr,"namelist_file=\"%s\"\n",namelist_file?namelist_file:"<no System.map file>");
|
2002-02-02 04:17:29 +05:30
|
|
|
}
|