001: /*
002: * <copyright>
003: *
004: * Copyright 2003-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.tools.server.system.linux;
027:
028: import java.io.BufferedReader;
029: import java.io.IOException;
030: import java.io.InputStream;
031: import java.io.InputStreamReader;
032: import java.util.ArrayList;
033: import java.util.List;
034:
035: import org.cougaar.tools.server.system.ProcessStatus;
036: import org.cougaar.tools.server.system.ProcessStatusReader;
037:
038: /**
039: * Linux-specific implementation of a
040: * <code>ProcessStatusReader</code>.
041: *
042: * @see ProcessStatusReader
043: * @see org.cougaar.tools.server.system.SystemAccessFactory
044: */
045: public class LinuxProcessStatusReader implements ProcessStatusReader {
046:
047: /**
048: * This works for "procps version 2.0.7" and <i>maybe</i>
049: * other "ps" implementations -- hopefully it's POSIX
050: * compliant.
051: */
052: private static final String[] LINUX_PS_SHORT = { "/bin/ps", "-o",
053: "pid,ppid,user,lstart,cmd", "-H", "--width", "1000",
054: "--sort=pid", "--no-headers", };
055:
056: private static final String[] LINUX_PS_ALL;
057: static {
058: // tack on a "-A"
059: String[] sa = new String[LINUX_PS_SHORT.length + 1];
060: for (int i = 0; i < LINUX_PS_SHORT.length; i++) {
061: sa[i] = LINUX_PS_SHORT[i];
062: }
063: sa[LINUX_PS_SHORT.length] = "-A";
064: LINUX_PS_ALL = sa;
065: }
066:
067: // format for "lstart"
068: private static final String LONG_TIME_FORMAT = "EEE MMM d hh:mm:ss yyyy";
069:
070: private static final int LONG_TIME_SPACES;
071: static {
072: int n = 0;
073: for (int i = 0; i < LONG_TIME_FORMAT.length(); i++) {
074: if (LONG_TIME_FORMAT.charAt(i) == ' ') {
075: n++;
076: }
077: }
078: LONG_TIME_SPACES = n;
079: }
080:
081: // formatter
082: private static final java.text.SimpleDateFormat TIME_FORMATTER = new java.text.SimpleDateFormat(
083: LONG_TIME_FORMAT);
084:
085: public LinuxProcessStatusReader() {
086: // check "os.name"?
087: }
088:
089: public String[] getCommandLine(boolean findAll) {
090: if (findAll) {
091: return LINUX_PS_ALL;
092: } else {
093: return LINUX_PS_SHORT;
094: }
095: }
096:
097: public final ProcessStatus[] parseResponse(InputStream in)
098: throws IOException {
099: return parseResponse(new BufferedReader(new InputStreamReader(
100: in)));
101: }
102:
103: public final ProcessStatus[] parseResponse(BufferedReader br)
104: throws IOException {
105: return parse0(br);
106: }
107:
108: private static final ProcessStatus[] parse0(BufferedReader br)
109: throws IOException {
110:
111: ArrayList l = new ArrayList();
112: ArrayList lKids = new ArrayList();
113:
114: Position pos = new Position();
115: while (true) {
116: // read line
117: String line = br.readLine();
118: if (line == null) {
119: break;
120: }
121:
122: // parse line
123: pos.i = 0;
124: long pid = parsePID(line, pos);
125: long ppid = parsePPID(line, pos);
126: String user = parseUser(line, pos);
127: long lstart = parseLStart(line, pos);
128: String cmd = parseCmd(line, pos);
129:
130: // find parent
131: ProcessStatus parent = null;
132: List parentChildren = null;
133: for (int n = l.size() - 1; n >= 0; n--) {
134: ProcessStatus pn = (ProcessStatus) l.get(n);
135: if (pn.getProcessIdentifier() == ppid) {
136: parent = pn;
137: parentChildren = (List) lKids.get(n);
138: break;
139: }
140: }
141:
142: List selfChildren = new ArrayList(13);
143:
144: // create entry
145: ProcessStatus self = new ProcessStatus(parent,
146: selfChildren, pid, ppid, lstart, user, cmd);
147:
148: if (parentChildren != null) {
149: parentChildren.add(self);
150: }
151:
152: l.add(self);
153: lKids.add(selfChildren);
154: }
155:
156: // convert to array
157: return (ProcessStatus[]) l.toArray(new ProcessStatus[l.size()]);
158: }
159:
160: private static class Position {
161: // no pass-by-reference...
162: public int i;
163: }
164:
165: private static long parsePID(String s, Position pos) {
166: // expecting (' '* PID ' ')
167: long pid;
168: try {
169: int i = pos.i;
170: while (s.charAt(i) == ' ') {
171: ++i;
172: }
173: int j = s.indexOf(' ', i);
174: String spid = s.substring(i, j);
175: pid = Long.parseLong(spid);
176: pos.i = j + 1;
177: } catch (RuntimeException re) {
178: throw new IllegalArgumentException("Illegal pid: \"" + s
179: + "\"");
180: }
181: return pid;
182: }
183:
184: private static long parsePPID(String s, Position pos) {
185: long ppid;
186: try {
187: int i = pos.i;
188: while (s.charAt(i) == ' ') {
189: ++i;
190: }
191: int j = s.indexOf(' ', i);
192: String sppid = s.substring(i, j);
193: ppid = Long.parseLong(sppid);
194: pos.i = j + 1;
195: } catch (RuntimeException re) {
196: throw new IllegalArgumentException("Illegal ppid: \"" + s
197: + "\"");
198: }
199: return ppid;
200: }
201:
202: private static String parseUser(String s, Position pos) {
203: String suser;
204: try {
205: int i = pos.i;
206: while (s.charAt(i) == ' ') {
207: ++i;
208: }
209: int j = s.indexOf(' ', i);
210: suser = s.substring(i, j);
211: pos.i = j + 1;
212: } catch (RuntimeException re) {
213: throw new IllegalArgumentException("Illegal user: \"" + s
214: + "\"");
215: }
216: return suser;
217: }
218:
219: private static long parseLStart(String s, Position pos) {
220: // expecting something like:
221: //
222: // "Tue Oct 16 17:57:12 2001"
223: //
224: // FIXME: this is very fragile!
225: long time;
226: try {
227: int i = pos.i;
228: while (s.charAt(i) == ' ') {
229: ++i;
230: }
231: // find end of date
232: int j = i;
233: for (int x = 0; x <= LONG_TIME_SPACES; x++) {
234: j = s.indexOf(' ', j + 1);
235: while (s.charAt(j) == ' ') {
236: ++j;
237: }
238: }
239: String sstart = s.substring(i, j);
240: time = parseLongDate(sstart);
241: pos.i = j;
242: } catch (RuntimeException re) {
243: throw new IllegalArgumentException("Illegal lstart: \"" + s
244: + "\"");
245: }
246: return time;
247: }
248:
249: private static String parseCmd(String s, Position pos) {
250: String scmd;
251: try {
252: int i = pos.i;
253: while (s.charAt(i) == ' ') {
254: ++i;
255: }
256: scmd = s.substring(i);
257: pos.i = s.length();
258: } catch (RuntimeException re) {
259: throw new IllegalArgumentException("Illegal cmd: \"" + s
260: + "\"");
261: }
262: return scmd;
263: }
264:
265: protected static long parseLongDate(String lstart) {
266: java.text.ParsePosition p = new java.text.ParsePosition(0);
267: java.util.Date d;
268: synchronized (TIME_FORMATTER) {
269: d = TIME_FORMATTER.parse(lstart, p);
270: }
271: return d.getTime();
272: }
273:
274: }
|