Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: efdfb9a31bbd4599db0cca63faab376736100e8d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*******************************************************************************
 * Copyright (c) 2006,2012 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - Jeff Briggs, Henry Hughes, Ryan Morse
 *******************************************************************************/

package org.eclipse.linuxtools.internal.systemtap.ui.ide.structures;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.linuxtools.internal.systemtap.ui.ide.IDEPlugin;
import org.eclipse.linuxtools.internal.systemtap.ui.ide.StringOutputStream;
import org.eclipse.linuxtools.internal.systemtap.ui.ide.preferences.EnvironmentVariablesPreferencePage;
import org.eclipse.linuxtools.internal.systemtap.ui.ide.preferences.IDEPreferenceConstants;
import org.eclipse.linuxtools.systemtap.structures.runnable.StringStreamGobbler;
import org.eclipse.linuxtools.systemtap.ui.consolelog.internal.ConsoleLogPlugin;
import org.eclipse.linuxtools.systemtap.ui.consolelog.preferences.ConsoleLogPreferenceConstants;
import org.eclipse.linuxtools.tools.launch.core.factory.LinuxtoolsProcessFactory;
import org.eclipse.linuxtools.tools.launch.core.factory.RuntimeProcessFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSchException;

/**
 * Runs stap -vp1 & stap -up2 in order to get all of the probes/functions
 * that are defined in the tapsets.  Builds probeAlias and function trees
 * with the values obtained from the tapsets.
 *
 * Ugly code is a result of two issues with getting stap output.  First,
 * many tapsets do not work under stap -up2.  Second since the output
 * is not a regular language, we can't create a nice lexor/parser combination
 * to do everything nicely.
 * @author Ryan Morse
 */
public abstract class TapsetParser extends Job {

    private static AtomicBoolean displayingError = new AtomicBoolean(false);
    private static AtomicBoolean displayingCredentialDialog = new AtomicBoolean(false);

    protected TapsetParser(String jobTitle) {
        super(jobTitle);
    }

    @Override
    protected void canceling() {
        getThread().interrupt();
    }

    /**
     * Generates a {@link Status} with the provided severity.
     */
    protected IStatus createStatus(int severity) {
        return new Status(severity, IDEPlugin.PLUGIN_ID, ""); //$NON-NLS-1$
    }

    /**
     * Runs stap with the given options and returns the output generated,
     * or <code>null</code> if the case of an error.
     * @param options String[] of any optional parameters to pass to stap
     * @param probe String containing the script to run stap on,
     * or <code>null</code> for scriptless commands
     * @param getErrors Set this to <code>true</code> if the script's error
     * stream contents should be returned instead of its standard output
     * @return The output generated from the stap run, or <code>null</code>
     * in the case of an error, or an empty string if the run was canceled.
     */
    protected String runStap(String[] options, String probe, boolean getErrors) {
        String[] args = null;
        String[] tapsets = IDEPlugin.getDefault().getPreferenceStore()
                .getString(IDEPreferenceConstants.P_TAPSETS).split(File.pathSeparator);
        boolean noTapsets = tapsets[0].trim().isEmpty();
        boolean noOptions = options[0].trim().isEmpty();
        final boolean remote = IDEPlugin.getDefault().getPreferenceStore().getBoolean(IDEPreferenceConstants.P_REMOTE_PROBES);

        int size = probe != null ? 2 : 1;
        if (!noTapsets) {
            size += tapsets.length<<1;
        }
        if (!noOptions) {
            size += options.length;
        }

        args = new String[size];
        args[0] = "stap"; //$NON-NLS-1$
        if (probe != null) {
            // Workaround for the fact that remote & local execution methods use string args differently
            args[size - 1] = !remote ? probe : '\'' + probe + '\'';
        }

        //Add extra tapset directories
        if (!noTapsets) {
            for (int i = 0; i < tapsets.length; i++) {
                args[1 + 2*i] = "-I"; //$NON-NLS-1$
                args[2 + 2*i] = tapsets[i];
            }
        }
        if (!noOptions) {
            for (int i = 0, s = noTapsets ? 1 : 1 + tapsets.length*2; i < options.length; i++) {
                args[s + i] = options[i];
            }
        }

        try {
            if (!remote) {
                return runLocalStap(args, getErrors);
            } else {
                return runRemoteStapAttempt(args, getErrors);
            }
        } catch (IOException e) {
            displayError(Messages.TapsetParser_ErrorRunningSystemtap, e.getMessage());
        } catch (InterruptedException e) {
            return ""; //$NON-NLS-1$
        }

        return null;
    }

    /**
     * Return an {@link IStatus} severity constant for the result of a call to
     * {@link TapsetParser#runStap(String[], String, boolean)}.
     * @param result The output generated by a call to {@link #runStap(String[], String, boolean)}.
     */
    protected int verifyRunResult(String result) {
        if (result == null) {
            return IStatus.ERROR;
        } else if (result.isEmpty()) {
            return IStatus.CANCEL;
        }
        return IStatus.OK;
    }

    private String runLocalStap(String[] args, boolean getErrors) throws IOException, InterruptedException {
        Process process = RuntimeProcessFactory.getFactory().exec(
                args, EnvironmentVariablesPreferencePage.getEnvironmentVariables(), null);
        if (process == null) {
            displayError(Messages.TapsetParser_CannotRunStapTitle, Messages.TapsetParser_CannotRunStapMessage);
            return null;
        }

        StringStreamGobbler gobbler = new StringStreamGobbler(process.getInputStream());
        StringStreamGobbler egobbler = null;
        gobbler.start();
        if (getErrors) {
            egobbler = new StringStreamGobbler(process.getErrorStream());
            egobbler.start();
        }
        process.waitFor();
        gobbler.stop();
        if (egobbler == null) {
            return gobbler.getOutput().toString();
        } else {
            egobbler.stop();
            return egobbler.getOutput().toString();
        }
    }

    private String runRemoteStapAttempt(String[] args, boolean getErrors) {
        int attemptsLeft = 3;
        while (true) {
            try {
                return runRemoteStap(args, getErrors);
            } catch (JSchException e) {
                if (!(e.getCause() instanceof ConnectException) || --attemptsLeft == 0) {
                    askIfEditCredentials();
                    return null;
                }
            }
        }
    }

    private String runRemoteStap(String[] args, boolean getErrors) throws JSchException {
        StringOutputStream str = new StringOutputStream();
        StringOutputStream strErr = new StringOutputStream();

        IPreferenceStore p = ConsoleLogPlugin.getDefault().getPreferenceStore();
        String user = p.getString(ConsoleLogPreferenceConstants.SCP_USER);
        String host = p.getString(ConsoleLogPreferenceConstants.HOST_NAME);
        String password = p.getString(ConsoleLogPreferenceConstants.SCP_PASSWORD);
        int port = p.getInt(ConsoleLogPreferenceConstants.PORT_NUMBER);

        Channel channel = LinuxtoolsProcessFactory.execRemoteAndWait(args, str, strErr, user, host, password,
                port, EnvironmentVariablesPreferencePage.getEnvironmentVariables());
        if (channel == null) {
            displayError(Messages.TapsetParser_CannotRunStapTitle, Messages.TapsetParser_CannotRunStapMessage);
        }

        return (!getErrors ? str : strErr).toString();
    }

    private void askIfEditCredentials() {
        if (displayingCredentialDialog.compareAndSet(false, true)) {
            PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
                @Override
                public void run() {
                    Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
                    MessageBox dialog = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
                    dialog.setText(Messages.TapsetParser_RemoteCredentialErrorTitle);
                    dialog.setMessage(Messages.TapsetParser_RemoteCredentialErrorMessage);
                    if (dialog.open() == SWT.YES) {
                        String pageID = "org.eclipse.linuxtools.systemtap.prefs.consoleLog"; //$NON-NLS-1$
                        PreferencesUtil.createPreferenceDialogOn(shell, pageID, new String[]{pageID}, null).open();
                    }
                    displayingCredentialDialog.set(false);
                }
            });
        }
    }

    private void displayError(final String title, final String error) {
        if (displayingError.compareAndSet(false, true)) {
            Display.getDefault().asyncExec(new Runnable() {
                @Override
                public void run() {
                    IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
                    MessageDialog.openWarning(window.getShell(), title, error);
                    displayingError.set(false);
                }
            });
        }
    }

}

Back to the top