tiny zone to run apache
Even if communities around Solaris Zones and available documentation
are great
I had difficulties to answer this simple question :
How to create a zone a small as possible to run only Apache/MySQL in it ?
I've just needed a web server (and MySQL) to run a site with very limited activity.
All this contained in a zone.
So I needed a zone with a minimum footprint which won't disturb me
on my host which is not a beast.
After trying to aggregate all I've read, I am not pretending
that this is the perfect answer but
here what I've done :
(I used a ZFS pool present on my host)
Once the zone is installed we can see that disk space is quite small Now use a SMF profile to disable all unused service (i.e in my case all but apache and MySQL) Once zone is booted and configured (using sysidcfg) for performance tuning
#zfs create tank/tinyzone
#zfs set mountpoint=/tinyzone
#zfs set quota=500M tank/tinyzone
...
#dispadmin -d FSS (need a reboot/init 6)
...
#zonecfg -z tinyzone
zonecfg:tinyzone> create
zonecfg:tinyzone> set zonepath=/tinyzone
zonecfg:tinyzone> set autoboot=true
zonecfg:tinyzone> set scheduling-class=FSS
zonecfg:tinyzone> set ip-type=shared
(on my host /opt contains lots of packages)
zonecfg:tinyzone> add inherit-pkg-dir
zonecfg:tinyzone:inherit-pkg-dir> set dir=/opt
zonecfg:tinyzone:inherit-pkg-dir> end
zonecfg:tinyzone> add net
zonecfg:tinyzone:net> set address=x.x.x.x
zonecfg:tinyzone:net> set physical=bge0
zonecfg:tinyzone:net> set defrouter=x.x.x.x
zonecfg:tinyzone:net> end
(global zone will receive a lot more shares)
zonecfg:tinyzone> set cpu-shares=1
zonecfg:tinyzone> add capped-memory
zonecfg:tinyzone:capped-memory> set physical=512M
zonecfg:tinyzone:capped-memory> set swap=512M
zonecfg:tinyzone:capped-memory> end
zonecfg:tinyzone> verify
zonecfg:tinyzone> commit
zonecfg:tinyzone> exit
...
#chmod 700 /tinyzone
#zonecfg -z tinyzone info
zonename: tinyzone
zonepath: /tinyzone
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
[cpu-shares: 1]
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
inherit-pkg-dir:
dir: /opt
net:
address: 1.2.3.4
physical: bge0
defrouter: 1.2.3.1
capped-memory:
physical: 512M
[swap: 512M]
rctl:
name: zone.cpu-shares
value: (priv=privileged,limit=1,action=none)
rctl:
name: zone.max-swap
value: (priv=privileged,limit=536870912,action=deny
zfs get available,used tank/tinyzone
NAME PROPERTY VALUE SOURCE
tank/tinyzone available 381M -
tank/tinyzone used 119M -
#svccfg extract > /tmp/tinyprofile
... go through the list inside /tmp/tinyprofile to disable everything not needed
#cp /tmp/tinyprofile /tinyzone/root/var/svc/profile/site.xm
check Apache and MySQL web site
et voila
prstat -Z
-----------------------------------------------------------
ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE
0 131 704M 847M 33% 1:42:30 15% global
4 32 126M 85M 3.3% 0:00:18 0.1% tinyzone
Posted at 07:49PM août 14, 2008 by ejannett in Unix | Comments[0]
taking snaphost and creating template of Xen domain
For testing purpose I've used vmware images. One of the advantages was to be able to take snapshots of an image.
And to make these snapshots a template for furture image creation.
When developing on windows platforms all this save you a lot of time.
Now I am using Xen on latest release of Solaris. This great but I was missing snapshots and templates.
Thank to ZFS I am happy again.
The trick is simple : use ZFS volume to create your guests and just use cloning and snapshot feature of ZFS.
In this example I use a file to create the zfs pool, this is not reliable but this is enough as we are testing
1 - Create a file.
#mkfile -n 10g /my-image-file
2 - Create a pool on that file.
#zpool create mypool /my-image-file
#zpool status mypool
pool: mypool
state: ONLINE
scrub: none requested
config:
NAME STATE READ WRITE CKSUM
mypool ONLINE 0 0 0
/my-image-file ONLINE 0 0 0
3 - Create a volume on that new created pool.
#zfs create -V 10g mypool/myhostdisk
4 - Create the guest on this new volume.
virt-install --name=foo --hvm --file-size=10 --ram=1024 --os-type=windows --vnc --cdrom=win.iso --file=/dev/zvol/dsk/mypool/myhostdisk
That's it ! each time you want a snapshot, shutdown the guest and take a snapshot of the volume.
Cloning the snapshot will give templates.
Posted at 10:08AM juil. 28, 2008 by ejannett in Operating Systems | Comments[0]
Problem about corrupted cacao SMF service
On solaris 1x the Common Agent Container is registered under SMF. Sometimes (mainly due
to user violent/wrong usage of packaging) the service configuration is corrupted and
trying to start CAC messages like the following ones may appear.
#cacaoadm start
svcs: Pattern
'svc:/application/management/common-agent-container-1:default' doesn't
match any instances
Error when reseting SMF service maintenance state:
[svc:/application/management/common-agent-container-1:default].
Error when trying to start SMF service:
[svc:/application/management/common-agent-container-1:default].
One way to recover from that is to uninstall the package and to cleanup the repository if needed.
Note that CAC configuration remains on the host across installations. Also note that operation will not
solve all possible corruptions but I hope this will help most of people facing that issue
#pkgrm SUNWcacaort
Be careful to only remove FMRI relative to your installation
#svcs svc:/application/management/common-agent-container\*
disabled Dec_03 svc:/application/management/common-agent-container-4:default
disabled Dec_03 svc:/application/management/common-agent-container-6:default
disabled Dec_03 svc:/application/management/common-agent-container-7:default
disabled Dec_03 svc:/application/management/common-agent-container-8:default
online Apr_02 svc:/application/management/common-agent-container-9:default
#svcprop -p common-agent-container/basedir svc:/application/management/common-agent-container\*
svc:/application/management/common-agent-container-9:default/:properties/common-agent-container/basedir astring /
svc:/application/management/common-agent-container-8:default/:properties/common-agent-container/basedir astring /
svc:/application/management/common-agent-container-7:default/:properties/common-agent-container/basedir astring /var/tmp/root/cacao_2.2/
svc:/application/management/common-agent-container-6:default/:properties/common-agent-container/basedir astring /var/tmp/kkoteste/cacao_2.1/
svc:/application/management/common-agent-container-4:default/:properties/common-agent-container/basedir astring /var/tmp/cacao_2.0/
here, 4,6 and 7 are obviously not ours
svccfg delete svc:/application/management/common-agent-container-8:default
svccfg delete svc:/application/management/common-agent-container-9:default
#pkgadd ....
#cacaoadm statusdefault instance is DISABLED at system startup.default instance is not running.
Posted at 10:43AM avr. 21, 2008 by ejannett in Common Agent Container FAQ | Comments[1]
How do I wait for a module to be ready
A common mistake is to not make the difference between
the status of the Common Agent Container and the status of modules deployed inside.
As any container, CAC may be in good shape while modules deployed aren't.
The command "cacaoadm status" gives you the status of the container but
to get the actual state and status of a module the command is cacaoadm status <module name>.
The container may be in three states:
# cacaoadm statusdefault instance is DISABLED at system startup.default instance is not running.
# cacaoadm status
default instance is DISABLED at system startup.
Smf monitoring process:
13400
Uptime: 0 day(s), 0:16
# cacaoadm status
default instance is DISABLED at system startup.
Daemon is running but not available. Try again as it might be starting."
The container may be still starting executing its own initilization phase but mainly busy to
start modules deployed inside. see here for details. The container is ready to serve as soon as
an uptime is printed.
All this as nothing to do with the satus of a modules deployed. The container will start a module but
the module can be actually not ready to serve :
If an application depends on a service(s) deployed in CAC (i.e a module(s)) . This application
must monitor the status of the module it is interested in and not the container itself.
This is done by "cacaoadm status <module name>".
Few examples of module'state/status :
# cacaoadm status com.sun.cacao.rbacOperational State:ENABLEDAdministrative State:UNLOCKEDAvailability Status:[]Module is in good health.
#cacaoadm status com.sun.cacao.efd
Module com.sun.cacao.efd has not been loaded.
Cause of the problem:[OFF_LINE]
#cacaoadm status com.sun.cacao.instrumOperational State:DISABLEDAdministrative State:UNLOCKEDAvailability Status:[OFF_LINE]
#cacaoadm status com.sun.scn.base.SCNBaseModule com.sun.scn.base.SCNBase has not been loaded.Cause of the problem:[FAILED]
#cacaoadm status com.sun.scn.SolarisAssetModuleModule com.sun.scn.SolarisAssetModule has not been loaded.Cause of the problem:[DEPENDENCY]
Another tips for a module developer is set correctly its dependencies. One of basics examples is connectors.
If a module offer a service using the RMI connector (if the client part of the applications access it
only using the RMI connector). If the developer knows that its entire logic will be down because if this,
the module descriptor file of the module should define a dependency on the RMI module.
Posted at 09:12AM avr. 21, 2008 by ejannett in Common Agent Container FAQ | Comments[0]
why the Common Agent Container (CACAO) take a long time to start or stop ?
One question we have time to time is about the time taken by the container to start.
The answer in 99.9 % of the case is : because of one module deployed inside.
0.1 % percent left are due to sub-processes as explain here.
The Common Agent Container only loaded with its core modules never take more thenfew seconds to start (include the start of the underlying jvm ).
For instance on a host (2 x UltraSPARC-IIIi (1280 MHz) - 2.50GB Mem)
the container initialisation takes 4~5 secondes. A big part of this is taken by the creation
and the start of modules.
As an example here are statistics displayed using a Dtrace script.
modules - time (secs/milliseconds)
startAdaptorsAndConnectors - 312
registerAdaptorsAndConnectors - 1375
register all modules - 82003
container start - 86893
In this case DTrace is really not the recommended way to take stats
as the jvm is really slowed down but it gives you an idea of how the time is dispatched.
Everything in the container start sequence (this is also true for the shutdown) is done sequentially:
container initialisation
-> connectors/adaptors creation
-> start modules in order (dependency order)
-> start connectors (connections are then allowed)
-> stop modules in order
-> stop connectors
container finalization
The benefit of this is simplicity and to ease the life of module developers. A module cannot (may not)
be disturbed while it is performing tricky actions like initislisation and cleanup. As connectors
are not opened, no request can be received.
The disadvantage of this is if somebody take a long time to complete, everything is blocked waiting.
Initialization and finalisation of a module (start and stop method) are supposed to be as short
as possible and bounded in time. If a module has to do perform some actions which may block
(db connection, remote host connection, execution of interactive process ...). The developper should
implement timeouts and/or use additional thread dedicated to "dangerous" phases.
By doing this there will be no risk to block or slow down the container. And all deployed modules
will enjoy beeing started on time.
Knowing that, here is what you can do to identify the root cause of a slow start or stop of the container.
When this happen on Solaris 10 and above, the cli command "/usr/sbincacaoadm start" will take
a long time to return. On other systems (Solaris9, Linux, hp-ux, windows) the CLI will return but
the container will take a long time to be ready to serve. issuing the "cacaoadm status" command
you will see messages like
default instance is DISABLED at system startup.
14834
14835
Daemon is running but not available. Try again as it might be starting.
Just having a look to the log file should help you to find out what happened.
First set a high level on the following filters.
cacaoadm set-filter --persistent com.sun.cacao.element=ALL
cacaoadm set-filter --persistent com.sun.cacao.container.impl=ALL
The container initialization would be logged but also (the most interesting part) the beginning
and the end of each modules initialisation. You have to look for entries from unsynchronizedDeployModule method
and entries from the ElementSupport support class. Here is an example with the RMI module
....
Feb 21, 2008 6:08:49 PM com.sun.cacao.container.impl.ContainerPrivate unsynchronizedDeployModule
FINER: Add the descriptor Module name: com.sun.cacao.rmi
Descriptor full path:/usr/lib/cacao/lib/tools/template/modules/com.sun.cacao.rmi.xml
Description: This module manages the secure and unsecure RMI connectors.
Version: 1.0
Module class: com.sun.cacao.rmi.impl.RMIModule
Initial admin State: UNLOCKED
Heap: 100
Instances Descriptor:
Dependencies: []
Parameters: {}
Cacao version supported: 2.1
Private paths: []
Public paths: [file:../../../../lib/cacao_rmi.jar]
Library paths: []
Ignored at startup: false
Enable on demand: false
Feb 21, 2008 6:08:50 PM com.sun.cacao.element.ElementSupport setAdministrativeState
FINE: Administrative state change to UNLOCKED : com.sun.cacao:type=ModuleManager,instance="com.sun.cacao.rmi"
Feb 21, 2008 6:08:50 PM com.sun.cacao.element.ElementSupport setAdministrativeState
FINE: Administrative state change to UNLOCKED : com.sun.cacao:type=module,instance="com.sun.cacao.rmi"
....
As you can see the start of this module begun at 6:08:49 to end more or less at 6:08:50.
You know now that the RMI module took around 1 second to start.
An administrative state set to UNLOCK for a module means 'started'
Looking at the log file like this should give you the name of the culprit.
High level filter can be time and disk consuming. When your investigation is completed
you should set them back to their default value (in our case null as only com.sun.cacao is set by default).
cacaoadm set-filter --persistent com.sun.cacao.element=null
cacaoadm set-filter --persistent com.sun.cacao.container.impl=null
Posted at 06:31PM févr. 21, 2008 by ejannett in Common Agent Container FAQ | Comments[0]
relocatable binaries and scripts
Once, somebody asked me about how to relocate scripts and binaries in a safe manner . Depending on what
you do it may not be as easy as looking in argv[0]. Hope this helps somebody else.
| #!/bin/sh where_am_i () { cmd=`dirname $1` case ${cmd} in /*) cannon_cmd=${cmd} ;; */*) _pwd=`pwd 2>/dev/null` cannon_cmd="${_pwd}/${cmd}" ;; *) echo "ousp..." exit 1 ;; esac echo "$cannon_cmd" | awk -F/ '{ realpath=""; skip_it=0; for (i=NF; i>0; i--) { if ($i == ".") continue; if (length($i) == 0&& i != 1) continue; if ($i == "..") {skip_it++; continue;} if (skip_it > 0 ) { skip_it--; continue; } if (length(realpath) > 0) { realpath=$i"/"realpath; } else { realpath=$i; } } } END {print realpath}' 2>/dev/null } res=`where_am_i $0` echo "resolved command line <$res>" |
this will produce output like
#/tmp/a.sh
resolved command line </tmp/>
#/var/tmp/..//../tmp/a.sh
resolved command line </tmp/>
#/var/tmp/..//../tmp/./a.sh
resolved command line </tmp/>
@ECHO OFF .... endlocal |
use FindBin; # add our module repository to perl @INC #.... later in a sub module my ($mod_package,$mod_name) = split (/::/,__PACKAGE__); |
#include <dlfcn.h>
Dl_info dli;
dladdr((void*)&main,&dli);
printf("resolved cmd : %s\n",(char*)mydlinfo.dli_fname);
max = pathconf("/",_PC_PATH_MAX);
buf = (char*)malloc(max + 1);
end = readlink("/proc/self/exe",buf,max);
buf[end] = '\0';
printf("resolved cmd : %s\n",buf);
struct ld_info *myld_info;
loadquery(L_GETINFO, buf, size);
myld_info = (struct ld_info *)buf;
printf("resolved cmd : %s\n",myld_info->ldinfo_filename);
struct shl_descriptor *desc;
shl_gethandle(PROG_HANDLE,&desc);
//Note : may need to prepend pwd to desc->filename
printf("resolved cmd : %s\n",desc->filename);
GetModuleFileName(NULL, buffer,<buffer length>);
printf("resolved cmd : %s\n",desc->filename);
Posted at 11:16AM févr. 06, 2008 by ejannett in Operating Systems | Comments[2]
How to get Common Agent Container/detached jvm dump
One of the frequently asked question is : My Jvm just crash but I cannot find any core dump of log.
All this may depend on host and/or Jvm configuration. The Common Agent Container is a service and
then run in background. It is not as easy as with console application to get any traces.
There are several methods I've used, here they are, just pick the one you prefer (some are not working on all jdks).
Using the fault probe of the Proc provider you can print the stack trace each time the jvm
triggers one. I've wrote a small DTrace script that you can use. For all running Jvms it will
print output like the following on case of failure. In that example I've hacked a jni call to trigger
a segmentation fault. (get the script)
[java: 4213/ 2] experiencing fault <address not mapped to object>, signal 11
libc.so.1`0xff1c5a70
libc.so.1`0xff2103ec
Interpreter
com/sun/cacao/agent/auth/UserPrincipal.internalGetUid(Ljava/lang/String;)I
com/sun/cacao/agent/auth/UserPrincipal.internalGetUid(Ljava/lang/String;)I
com/sun/cacao/agent/auth/UserPrincipal.getUid()I
com/sun/cacao/agent/auth/AssertMechanism.createSubject(Ljava/lang/String;Z)Ljavax/security/auth/Subject;
com/sun/cacao/container/impl/ContainerPrivate.internalStart(Ljava/lang/String;)V
com/sun/cacao/container/impl/ContainerPrivate.start(Ljava/lang/String;Ljava/lang/String;)V
com/sun/cacao/container/impl/ContainerPrivate.main([Ljava/lang/String;)V
StubRoutines (1)
libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x1e4
libjvm.so`jni_CallStaticVoidMethod+0x4b8
java`0x13a4c
libc.so.1`0xff245e28
unix`trap_cleanup+0x24
unix`trap+0x1b84
unix`utl0+0x4c
Posted at 07:24PM févr. 05, 2008 by ejannett in Common Agent Container FAQ | Comments[0]
start/stop of Common Agent Container hangs
One question which is raised more and more often is :
"why can I stop/start the Common Agent Container ?"
or
"why /usr/sbin/cacaoadm stop/start command never returns ?".
Users facing that are on Solaris 10/11. This is due to users' modules executing sub processes and
not doing proper cleanup when they are asked to stop. Another cause is user module start/stop method wrong implementation.
There are at least two rules that a module must follow :
# svcs -p -o CTID,SVC svc:/application/management/common-agent-container-1:default |
| ctstat -v -i `/usr/bin/svcs -H -o CTID svc:/application/management/common-agent-container-1:default` CTID ZONEID TYPE STATE HOLDER EVENTS QTIME NTIME 4924 0 process owned 7 0 - - cookie: 0x20 informative event set: none critical event set: core signal hwerr empty fatal event set: none parameter set: inherit regent member processes: 2536 2537 2785 2787 inherited contracts: none # pargs 2787 2787: /usr/sbin/ping -s 127.0.0.1 argv[0]: /usr/sbin/ping argv[1]: -s argv[2]: 127.0.0.1 |
| # /usr/sbin/cacaoadm stop (we are hanging here...) | # ptree -c `pgrep -x cacaoadm` [process contract 1] 1 /sbin/init [process contract 4] 7 /lib/svc/bin/svc.startd [process contract 87] 1346 gnome-terminal 27663 /bin/bash 27699 -bash 2842 /bin/sh /usr/sbin/cacaoadm stop 2951 /usr/sbin/svcadm disable -st svc:/application/management/common-agent-container |
| svcs -p -o CTID,STATE,SVC svc:/application/management/common-agent-container-1:default CTID STATE SVC 4924 online* application/management/common-agent-container-1 18:52:26 2787 ping | |
| (cacaoadm command is now completed) | #kill -INT 2787 |
| # svcs -p -o CTID,STATE,SVC svc:/application/management/common-agent-container-1:default CTID STATE SVC 4947 online application/management/common-agent-container-1 19:32:33 3590 launch 19:32:33 3591 java 19:33:42 3744 ctrun 19:33:42 3745 ping # ptree 3591 3590 /usr/lib/cacao/lib/tools/launch -w /usr/lib/cacao -f -U root -G sys -- /usr/jdk 3591 /usr/jdk/jdk1.6.0_03/bin/java -Xms4M -Xmx128M -classpath /usr/share/lib/jdmk/jd 3744 /usr/bin/ctrun -l child -o pgrponly /usr/lib/cacao/lib/tools/suexec /usr/sbin/p 3746 /usr/sbin/ping -s localhost bighal# ptree -c 3591 [process contract 1] 1 /sbin/init [process contract 4] 7 /lib/svc/bin/svc.startd [process contract 4947] 3590 /usr/lib/cacao/lib/tools/launch -w /usr/lib/cacao -f -U root -G sys -- /usr/jdk 3591 /usr/jdk/jdk1.6.0_03/bin/java -Xms4M -Xmx128M -classpath /usr/share/lib/jdmk/jd 3744 /usr/bin/ctrun -l child -o pgrponly /usr/lib/cacao/lib/tools/suexec /usr/sbin/p [process contract 4950] 3746 /usr/sbin/ping -s localhost # ptree -c 3745 [process contract 1] 1 /sbin/init [process contract 4] 7 /lib/svc/bin/svc.startd [process contract 4947] 3745 /usr/sbin/ping -s 127.0.0.1 |
Posted at 04:56PM janv. 13, 2008 by ejannett in Common Agent Container FAQ | Comments[0]
my new colleague
here is the picture of my new colleague at sun
I think he lied about his resume but he looks motivated....

Posted at 01:21PM août 10, 2007 by ejannett in Personal | Comments[0]
jumping sockets
One day I've faced an X-files situation on windows.
(now you should hear the sound
tudu..dudu..duduuuu from the trailer,... no ?
...never mind :-)).
One server was listening to connections on a specific address and port. so far so good...
Another instance of that server was launched (bound on the address/port by mistake) and I suddenly
saw a client communication already started with the first server ending with
the second one.
Posted at 06:51PM août 09, 2007 by ejannett in Windows | Comments[0]
Usual shell command lines translated for windows
I had to work on windows recently. As a standard Unix guy, I though that
you cannot use command line on windows, you have to install cygwin, mks etc...
I was curious and I've started to dig into cmd.exe usage. I've discovered that the windows command
line is far from being poor.
For some aspects I would even say that cmd.exe may be not less powerful than sh.
Here is a list of usual command I use translated to windows command tool.
Hope this help someone.
people crying for awk while doing scripting on windows , should have a
closer look to "FOR /?" :-)
/bin/ls -l |
dir /N /Q |
grep -i ^bla myfile.txt |
findstr /B /I "bla" myfile.txt |
grep -v -i ^bla myfile.txt |
findstr /V /B /I "bla" myfile.txt |
find /tmp -name *.c | xargs | grep blo |
findstr /S blo C:\\tmp *.c |
find /tmp -name *.c |
dir /S /B C:\\tmp\\*.c |
echo $? |
echo %ERRORLEVEL% |
ls *.c 2>/dev/null |
dir *.c 2>NUL |
pwd |
echo %CD% |
echo $0 |
echo %CMDCMDLINE% |
exit 12 |
exit /B 12 |
dirname $1 |
%~p1 |
basename $1 |
%~nx1 |
which $1 |
%~dp$PATH:1 |
env | grep TERM |
set TERM 2>NUL |
su - foo -c command |
runas /profile /user:foo command |
rsh myHost -l foo command |
rexec myHost -l foo command |
for file in `find /tmp -name *.txt` do echo `basename $file` done |
for /R C:\\TEMP %i in (*.txt) DO echo %~ni |
mount |
net use |
mount foo:/bar /mnt/bar |
net use Z: \\foo\bar [/USER:username /PERSISTENT:NO] |
| diff file1 file2 |
fc file1 file2 |
| echo -n "Enter a letter : " ; read foo |
set /P foo="Enter a letter : " |
| shutdown -g 120 -y -i 6 |
shutdown /r /l /f /dp:0:0 |
Posted at 12:48PM août 09, 2007 by ejannett in Windows | Comments[1]
Saut a l'elastique a Ponsonnas
Il y a quelques annees (2000) j'ai essaye le saut a l'elastique a ponsonnas
Je m'en souviens encore !
ps: a ne pas essayer avec des basquettes a scratchs...
Si vous dites "oui" de la tete assez vite ca fera un film :-)
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Posted at 11:34AM août 09, 2007 by ejannett in Personal | Comments[0]
Get rid of fopen file descriptor limits.
A usual problem for 32bits application using fopen call is the limitation
on the file descriptor stored in the FILE* structure. Even increasing
the quota on fd won't help. As soon as 255 is reach, fopen calls
fail. There is a lot blogs entries and discussion on the web regarding that
problem. This issue become even more complicated when you do not
own the code you are running (you are loading plugins, you are using third part code etc...). you cannot rewrite the executed code and you cannot prevent usage of fopen. Another example is when your aplication is a Java application and you
of course does not handle things like File object creation.
basically the trick about all this is to redirect all the call to fopen and open
to newly created calls. Like a filter. The filter will "catch" the calls to open and make sure that returned fd is greater than 255.
In another hand , fd returned for fopen (used by fopen)cannot be greater than 255, so the trick is to make sure that fd less than 255 are always available.
As I said, you can find already lot's of page on the web about this. The idea
is not mine at all but I did not find a complete implementation of it and
I was curious to try. Here is the code I used , I hope it can help somebody else.
The idea is to have a new implementation of the open call. The real open is
called to actually open the file but the file descriptor returned is then
duplicate on a new file descriptor greater then 255. We have to know when we
(new open) are called from an fopen call because is that case , the fd returned must not be duplicated (hoping that the fd returned is less than 255)
To make that trick usable for non provileged user (or user with low quota)
we are using reasonable file descriptor range:
0 to 128 are dedicated to fopen
128 to current file descriptor limit are dedicated to open.
Note : calls to dlsym should also be protected by mutex.
This code as to be used as a shared library
cc -G -o libnewopen.so
and used using LD_PRELOAD
LD_PRELOAD=./libnewopen.so ./<your progam>
#include <stdio.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <thread.h>
#include <synch.h>
#include <sys/resource.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef _DEBUG
#define TRACE(A) printf A;
#else
#define TRACE(A)
#endif
#pragma init (stdio_filter_init)
#pragma fini (stdio_filter_fini)
static thread_key_t stdio_filter_key = NULL;
static int fd_max = 0;
static short safe = 1;
static mutex_t fd_lock;
void stdio_filter_init(void *arg);
void stdio_filter_fini(void *arg);
static void init_thread_data();
static void mark_fopen_as_called(short called);
static short is_fopen_called();
FILE *fopen(const char *filename, const char *mode);
static int get_free_fd();
int open(const char *path, int oflag, ...);
/*
* - the filter must be thread safe.
* - When we enter an fopen call we set a flag to warn open to not duplicate.
* - we also need a mutex to be thrad safe when we choose a new file descriptor to return
*/
void stdio_filter_init(void *arg) {
struct rlimit lim;
if(thr_keycreate(&stdio_filter_key,NULL)) {
/*we cannot protect thread*/
/*disable all mechanism*/
safe = 0;
TRACE(("warning not safe mode\n"));
}
getrlimit(RLIMIT_NOFILE,&lim);
fd_max = lim.rlim_cur;
mutex_init(&fd_lock,USYNC_THREAD,NULL);
TRACE(("init done\n"));
}
void stdio_filter_fini(void *arg){
mutex_destroy(&fd_lock);
TRACE(("fini done\n"));
}
static void init_thread_data() {
short *thr_data = NULL;
if (!safe) return;
thr_getspecific(stdio_filter_key, (void**)&thr_data);
if (thr_data == NULL) {
thr_data = (short*)calloc(1,sizeof(short));
thr_setspecific(stdio_filter_key, (void*)thr_data);
}
}
static void mark_fopen_as_called(short called) {
short *thr_data = NULL;
if (!safe) return;
thr_getspecific(stdio_filter_key, (void**)&thr_data);
*thr_data = called;
thr_setspecific(stdio_filter_key, (void*)thr_data);
TRACE(("fopen marked as [%d]\n",called));
}
static short is_fopen_called() {
short *thr_data = NULL;
if (!safe) return 0;
thr_getspecific(stdio_filter_key, (void**)&thr_data);
return (*thr_data == 1);
}
FILE *fopen(const char *filename, const char *mode) {
FILE *file = NULL;
static void *(*actualfunction)();
init_thread_data();
if (!actualfunction) {
actualfunction = (void *(*)()) dlsym(RTLD_NEXT, "fopen");
}
if (safe) {
/*if not safe : bypass our filter*/
/*warn underlying open function that we are called from fopen*/
mark_fopen_as_called(1);
}
file = actualfunction(filename, mode);
if (safe) {
/*if not safe : bypass our filter*/
mark_fopen_as_called(0);
}
return(file);
}
static int get_free_fd() {
int idx;
for (idx = 128 ; idx < fd_max; idx++) {
/*check if fd is free*/
if (fcntl(idx,F_GETFD,0) == -1 && errno == EBADF) {
TRACE(("get_free_fd : fcntl on %5d returned [%d]\n",idx,errno))
return idx;
}
}
return(-1);
}
int open(const char *path, int oflag, ...) {
static void *(*actualfunction)();
int fd;
int new_fd;
va_list ap;
mode_t open_mode = NULL;
if (!actualfunction) {
actualfunction = (void *(*)()) dlsym(RTLD_NEXT, "open");
}
init_thread_data();
if ((oflag & O_CREAT)) {
TRACE(("+++++++++++++ O_CREAT is used\n"));
va_start(ap,oflag);
open_mode = va_arg(ap,mode_t);
va_end(ap);
} else {
TRACE(("+++++++++++++ O_CREAT is NOT used\n"));
open_mode = (mode_t)-1;
}
if (open_mode != (mode_t)-1) {
TRACE(("calling real open(%s,%d,%d)\n",path,oflag,open_mode));
fd = (int(*)(char*,int))actualfunction (path,oflag,open_mode);
} else {
TRACE(("calling real open(%s,%d)\n",path,oflag));
fd = (int(*)(char*,int,int))actualfunction (path,oflag);
}
if (!is_fopen_called()) {
/*not called from fopen, it is safe to push the fd further*/
(void)mutex_lock(&fd_lock);
new_fd = get_free_fd();
if (new_fd == -1) {
TRACE(("warning failed to get a free fd returning [%d]\n",fd));
new_fd = fd;
} else {
dup2(fd,new_fd);
close(fd);
TRACE(("open -> returning [%d] instead of [%d]\n",new_fd,fd));
}
(void)mutex_unlock(&fd_lock);
} else {
new_fd = fd;
}
return(new_fd);
}
Posted at 07:41PM août 08, 2007 by ejannett in Common | Comments[0]
Who is stealing my port ?
I often had to deal with problems about port already in use.
The main question
was why my server cannot bind on port xxx ? On Linux the
--program
option of netstat
show you the id of the process currently owning a specific socket
connection.
Solaris's
netstat command does
not have this option. Tired to scan the
/proc with
pfiles I've made a
small script. I hope it can be useful to somebody else.
#!/bin/sh
if [ $# -ne 1 ]
then
echo "usage $0 <port number>"
exit 1
fi
PORT=$1
echo "looking for process consuming port $PORT"
old=`pwd`
cd /proc
for pid in *
do
/usr/bin/pfiles $pid 2>/dev/null | /usr/bin/nawk -v port_num=$PORT '
$0 ~ /^[0-9]*:/ {
pid=$1
program=$2
}
$1 ~ /^[\t ]*sockname/ && $5 == port_num {
printf ("program [%d:%s] is bounded on %s:%d\n",pid,program,$3,port_num)
}'
done
cd $old
Posted at 07:40PM août 08, 2007 by ejannett in Unix | Comments[3]
get stack trace of a detached jvm
To get the stack trace of a running java process the usual way is to hit Ctrl-\ on the terminal.
The jvm then print out its current state and threads'stacks.
This become a problem when the Java program is detached from the terminal as all the outputs are then discarded.
Starting to JDK5, the jstack tool is here to help or when you own the code running into the jvm and/or you can change
the way the jvm is launched an easy way is to redirect the standard streams to log file and then to send the
QUIT signal to the jvm pid.
I had to deal with another situation in which jvm was running on jdk 4 and It was not possible to change anything about it.
The trick I then used was to write a small script which catch all the write calls on stderr on the jvm .
The script use strace(1) on Linux and truss(1) on Solaris to
catch what is passed to write calls on
file descriptor 1.
This script is available here :
catch_vm_dump.tcl

Posted at 07:40PM août 08, 2007 by ejannett in Unix | Comments[0]
Today's Page Hits: 10