Fixed open descriptor issue with agentupdate on linux/freebsd

Bryan Roe committed Jan 27, 2021 at 00:43 UTC fe9baf0e8ff07eaf171c08cc064f3e60009ff058
2 files changed +195 -7
agents/meshcore.js
+92 -3
@@ -3760,7 +3760,87 @@ function sendAgentMessage(msg, icon) {
3760 sendAgentMessage.messages[sendAgentMessage.nextid++] = { msg: msg, icon: icon };
3761 require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: sendAgentMessage.messages });
3762 }
3763 -
3763 +function getOpenDescriptors()
3764 +{
3765 + switch (process.platform)
3766 + {
3767 + case "freebsd":
3768 + var child = require('child_process').execFile('/bin/sh', ['sh']);
3769 + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3770 + child.stderr.on('data', function (c) { });
3771 +
3772 + child.stdin.write("procstat -f " + process.pid + " | tr '\\n' '`' | awk -F'`' '");
3773 + child.stdin.write('{');
3774 + child.stdin.write(' DEL="";');
3775 + child.stdin.write(' printf "[";');
3776 + child.stdin.write(' for(i=1;i<NF;++i)');
3777 + child.stdin.write(' {');
3778 + child.stdin.write(' A=split($i,B," ");');
3779 + child.stdin.write(' if(B[3] ~ /^[0-9]/)');
3780 + child.stdin.write(' {');
3781 + child.stdin.write(' printf "%s%s", DEL, B[3];');
3782 + child.stdin.write(' DEL=",";');
3783 + child.stdin.write(' }');
3784 + child.stdin.write(' }');
3785 + child.stdin.write(' printf "]";');
3786 + child.stdin.write("}'");
3787 +
3788 + child.stdin.write('\nexit\n');
3789 + child.waitExit();
3790 +
3791 + try
3792 + {
3793 + return (JSON.parse(child.stdout.str.trim()));
3794 + }
3795 + catch (e)
3796 + {
3797 + return ([]);
3798 + }
3799 + break;
3800 + case "linux":
3801 + var child = require('child_process').execFile('/bin/sh', ['sh']);
3802 + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3803 + child.stderr.on('data', function (c) { });
3804 +
3805 + child.stdin.write("ls /proc/" + process.pid + "/fd | tr '\\n' '`' | awk -F'`' '");
3806 + child.stdin.write('{');
3807 + child.stdin.write(' printf "[";');
3808 + child.stdin.write(' DEL="";');
3809 + child.stdin.write(' for(i=1;i<NF;++i)');
3810 + child.stdin.write(' {');
3811 + child.stdin.write(' printf "%s%s",DEL,$i;');
3812 + child.stdin.write(' DEL=",";');
3813 + child.stdin.write(' }');
3814 + child.stdin.write(' printf "]";');
3815 + child.stdin.write("}'");
3816 + child.stdin.write('\nexit\n');
3817 + child.waitExit();
3818 +
3819 + try
3820 + {
3821 + return (JSON.parse(child.stdout.str.trim()));
3822 + }
3823 + catch (e)
3824 + {
3825 + return ([]);
3826 + }
3827 + break;
3828 + default:
3829 + return ([]);
3830 + }
3831 +}
3832 +function closeDescriptors(libc, descriptors)
3833 +{
3834 + var fd = null;
3835 + while (descriptors.length > 0)
3836 + {
3837 + fd = descriptors.pop();
3838 + if (fd > 2)
3839 + {
3840 + libc.close(fd);
3841 + }
3842 + }
3843 +}
3844 function linux_execv(name, agentfilename, sessionid) {
3845 var libs = require('monitor-info').getLibInfo('libc');
3846 var libc = null;
@@ -3778,6 +3858,7 @@ function linux_execv(name, agentfilename, sessionid) {
3858 if (libc != null) {
3859 try {
3860 libc.CreateMethod('execv');
3861 + libc.CreateMethod('close');
3862 }
3863 catch (e) {
3864 libc = null;
@@ -3803,7 +3884,7 @@ function linux_execv(name, agentfilename, sessionid) {
3884
3885 var i;
3886 var args;
3806 - var argarr = [];
3887 + var argarr = [process.execPath];
3888 var path = require('_GenericMarshal').CreateVariable(process.execPath);
3889
3890 if (require('MeshAgent').getStartupOptions != null) {
@@ -3819,6 +3900,9 @@ function linux_execv(name, agentfilename, sessionid) {
3900 arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
3901 }
3902
3903 + var descriptors = getOpenDescriptors();
3904 + closeDescriptors(libc, descriptors);
3905 +
3906 libc.execv(path, args);
3907 if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
3908 sendAgentMessage('Self Update failed because execv() failed', 3);
@@ -3849,6 +3933,7 @@ function bsd_execv(name, agentfilename, sessionid) {
3933 try {
3934 libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
3935 libc.CreateMethod('execv');
3936 + libc.CreateMethod('close');
3937 }
3938 catch (e) {
3939 if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
@@ -3858,7 +3943,7 @@ function bsd_execv(name, agentfilename, sessionid) {
3943
3944 var i;
3945 var path = require('_GenericMarshal').CreateVariable(process.execPath);
3861 - var argarr = [];
3946 + var argarr = [process.execPath];
3947 var args;
3948 var options = require('MeshAgent').getStartupOptions();
3949 for (i in options) {
@@ -3871,6 +3956,10 @@ function bsd_execv(name, agentfilename, sessionid) {
3956 }
3957
3958 if (sessionid != null) { sendConsoleText('Restarting service via execv()', sessionid) }
3959 +
3960 + var descriptors = getOpenDescriptors();
3961 + closeDescriptors(libc, descriptors);
3962 +
3963 libc.execv(path, args);
3964 if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
3965 sendAgentMessage('Self Update failed because execv() failed', 3);
agents/recoverycore.js
+103 -4
@@ -71,6 +71,77 @@ function MeshServerLogEx(id, args, msg, state) {
71 require('MeshAgent').SendCommand(msg);
72 }
73
74 +function getOpenDescriptors()
75 +{
76 + switch(process.platform)
77 + {
78 + case "freebsd":
79 + var child = require('child_process').execFile('/bin/sh', ['sh']);
80 + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
81 + child.stderr.on('data', function (c) { });
82 +
83 + child.stdin.write("procstat -f " + process.pid + " | tr '\\n' '`' | awk -F'`' '");
84 + child.stdin.write('{');
85 + child.stdin.write(' DEL="";');
86 + child.stdin.write(' printf "[";');
87 + child.stdin.write(' for(i=1;i<NF;++i)');
88 + child.stdin.write(' {');
89 + child.stdin.write(' A=split($i,B," ");');
90 + child.stdin.write(' if(B[3] ~ /^[0-9]/)');
91 + child.stdin.write(' {');
92 + child.stdin.write(' printf "%s%s", DEL, B[3];');
93 + child.stdin.write(' DEL=",";');
94 + child.stdin.write(' }');
95 + child.stdin.write(' }');
96 + child.stdin.write(' printf "]";');
97 + child.stdin.write("}'");
98 +
99 + child.stdin.write('\nexit\n');
100 + child.waitExit();
101 +
102 + try
103 + {
104 + return(JSON.parse(child.stdout.str.trim()));
105 + }
106 + catch(e)
107 + {
108 + return ([]);
109 + }
110 + break;
111 + case "linux":
112 + var child = require('child_process').execFile('/bin/sh', ['sh']);
113 + child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
114 + child.stderr.on('data', function (c) { });
115 +
116 + child.stdin.write("ls /proc/" + process.pid + "/fd | tr '\\n' '`' | awk -F'`' '");
117 + child.stdin.write('{');
118 + child.stdin.write(' printf "[";');
119 + child.stdin.write(' DEL="";');
120 + child.stdin.write(' for(i=1;i<NF;++i)');
121 + child.stdin.write(' {');
122 + child.stdin.write(' printf "%s%s",DEL,$i;');
123 + child.stdin.write(' DEL=",";');
124 + child.stdin.write(' }');
125 + child.stdin.write(' printf "]";');
126 + child.stdin.write("}'");
127 + child.stdin.write('\nexit\n');
128 + child.waitExit();
129 +
130 + try
131 + {
132 + return (JSON.parse(child.stdout.str.trim()));
133 + }
134 + catch (e)
135 + {
136 + return ([]);
137 + }
138 + break;
139 + default:
140 + return ([]);
141 + }
142 +}
143 +
144 +
145 function pathjoin() {
146 var x = [];
147 for (var i in arguments) {
@@ -89,6 +160,20 @@ function pathjoin() {
160 // Replace a string with a number if the string is an exact number
161 function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
162
163 +
164 +function closeDescriptors(libc, descriptors)
165 +{
166 + var fd = null;
167 + while(descriptors.length>0)
168 + {
169 + fd = descriptors.pop();
170 + if(fd > 2)
171 + {
172 + libc.close(fd);
173 + }
174 + }
175 +}
176 +
177 function linux_execv(name, agentfilename, sessionid) {
178 var libs = require('monitor-info').getLibInfo('libc');
179 var libc = null;
@@ -104,8 +189,10 @@ function linux_execv(name, agentfilename, sessionid) {
189 }
190 }
191 if (libc != null) {
107 - try {
192 + try
193 + {
194 libc.CreateMethod('execv');
195 + libc.CreateMethod('close');
196 }
197 catch (e) {
198 libc = null;
@@ -131,7 +218,7 @@ function linux_execv(name, agentfilename, sessionid) {
218
219 var i;
220 var args;
134 - var argarr = [];
221 + var argarr = [process.execPath];
222 var path = require('_GenericMarshal').CreateVariable(process.execPath);
223
224 if (require('MeshAgent').getStartupOptions != null) {
@@ -147,6 +234,9 @@ function linux_execv(name, agentfilename, sessionid) {
234 arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
235 }
236
237 + var descriptors = getOpenDescriptors();
238 + closeDescriptors(libc, descriptors);
239 +
240 libc.execv(path, args);
241 if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
242 sendAgentMessage('Self Update failed because execv() failed', 3);
@@ -174,9 +264,11 @@ function bsd_execv(name, agentfilename, sessionid) {
264 }
265
266 var libc = null;
177 - try {
267 + try
268 + {
269 libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
270 libc.CreateMethod('execv');
271 + libc.CreateMethod('close');
272 }
273 catch (e) {
274 if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
@@ -186,7 +278,7 @@ function bsd_execv(name, agentfilename, sessionid) {
278
279 var i;
280 var path = require('_GenericMarshal').CreateVariable(process.execPath);
189 - var argarr = [];
281 + var argarr = [process.execPath];
282 var args;
283 var options = require('MeshAgent').getStartupOptions();
284 for (i in options) {
@@ -199,6 +291,10 @@ function bsd_execv(name, agentfilename, sessionid) {
291 }
292
293 if (sessionid != null) { sendConsoleText('Restarting service via execv()', sessionid) }
294 +
295 + var descriptors = getOpenDescriptors();
296 + closeDescriptors(libc, descriptors);
297 +
298 libc.execv(path, args);
299 if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
300 sendAgentMessage('Self Update failed because execv() failed', 3);
@@ -905,6 +1001,9 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
1001 case 'help':
1002 response = "Available commands are: agentupdate, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
1003 break;
1004 + case '_descriptors':
1005 + response = 'Open Descriptors: ' + JSON.stringify(getOpenDescriptors());
1006 + break;
1007 case 'versions':
1008 response = JSON.stringify(process.versions, null, ' ');
1009 break;