/** * Creates a ZFS file system to migrate the data to. * * <p> * This has to be done while we still have an interactive access with the user, since it involves the password. * * <p> * An exception will be thrown if the operation fails. A normal completion means a success. * * @return * The ZFS dataset name to migrate the data to. */ private String createZfsFileSystem(final TaskListener listener, String rootUsername, String rootPassword) throws IOException, InterruptedException, ZFSException { // capture the UID that Hudson runs under // so that we can allow this user to do everything on this new partition final int uid = LIBC.geteuid(); final int gid = LIBC.getegid(); passwd pwd = LIBC.getpwuid(uid); if(pwd==null) throw new IOException("Failed to obtain the current user information for "+uid); final String userName = pwd.pw_name; final File home = Jenkins.getInstance().getRootDir(); // this is the actual creation of the file system. // return true indicating a success return SU.execute(listener, rootUsername, rootPassword, new Create(listener, home, uid, gid, userName)); } private static class Create extends MasterToSlaveCallable<String, IOException> {
hudson.setMountPoint(dir); hudson.mount(); if(LIBC.chown(dir.getPath(),uid,gid)!=0) throw new IOException("Failed to chown "+dir); hudson.unmount();
public void restart() throws Exception { // close all files upon exec, except stdin, stdout, and stderr int sz = LIBC.getdtablesize(); for (int i = 3; i < sz; i++) { int flags = LIBC.fcntl(i, F_GETFD); if (flags < 0) continue; LIBC.fcntl(i, F_SETFD, flags | FD_CLOEXEC); } // exec to self String exe = Daemon.getCurrentExecutable(); LIBC.execv(exe, new StringArray(args.toArray(new String[args.size()]))); throw new IOException("Failed to exec '" + exe + "' " + LIBC.strerror(Native.getLastError())); }
@Override public boolean canWork() { try { if (File.pathSeparatorChar!=':') return false; // quick test to reject non-Unix without loading all the rest of the classes args = JavaVMArguments.current(); // go through the whole motion to make sure all the relevant classes are loaded now LIBC.getdtablesize(); int v = LIBC.fcntl(99999, F_GETFD); LIBC.fcntl(99999, F_SETFD, v); Daemon.getCurrentExecutable(); LIBC.execv("positively/no/such/executable", new StringArray(new String[]{"a","b","c"})); return true; } catch (UnsupportedOperationException | LinkageError | IOException e) { LOGGER.log(FINE, getClass()+" unsuitable", e); return false; } }
@Override public void run() { try { Thread.sleep(5000); // close all descriptors on exec except stdin,out,err int sz = LIBC.getdtablesize(); for(int i=3; i<sz; i++) { int flags = LIBC.fcntl(i, F_GETFD); if(flags<0) continue; LIBC.fcntl(i, F_SETFD,flags| FD_CLOEXEC); } // re-exec with the system property to indicate where to migrate the data to. // the 2nd phase is implemented in the migrate method. JavaVMArguments args = JavaVMArguments.current(); args.setSystemProperty(ZFSInstaller.class.getName()+".migrate",datasetName); Daemon.selfExec(args); } catch (InterruptedException | IOException e) { LOGGER.log(Level.SEVERE, "Restart failed",e); } } }.start();
private void process(final File file) { assert file != null; if (file.isFile()) { if (Functions.isMustangOrAbove()) { if (!file.setExecutable(true, false)) { log.error("Failed to chmod: {}", file); } } else { try { GNUCLibrary.LIBC.chmod(file.getAbsolutePath(), mode); } catch (LinkageError e) { // if JNA is unavailable, fall back PosixAPI.get().chmod(file.getAbsolutePath(), mode); } } } else { File[] children = file.listFiles(); if (children != null) { for (File child : children) { process(child); } } } } }
while(true) { if(LIBC.sysctl(MIB_PROC_ALL,3, NULL, size, NULL, ref)!=0) throw new IOException("Failed to obtain memory requirement: "+LIBC.strerror(Native.getLastError())); if(LIBC.sysctl(MIB_PROC_ALL,3, m, size, NULL, ref)!=0) { if(Native.getLastError()==ENOMEM && nRetry++<16) continue; // retry throw new IOException("Failed to call kern.proc.all: "+LIBC.strerror(Native.getLastError()));
@Override public void restart() throws IOException, InterruptedException { Jenkins jenkins = Jenkins.getInstanceOrNull(); // guard against repeated concurrent calls to restart try { if (jenkins != null) { jenkins.cleanUp(); } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to clean up. Restart will continue.", e); } // close all files upon exec, except stdin, stdout, and stderr int sz = LIBC.getdtablesize(); for(int i=3; i<sz; i++) { int flags = LIBC.fcntl(i, F_GETFD); if(flags<0) continue; LIBC.fcntl(i, F_SETFD,flags| FD_CLOEXEC); } // exec to self String exe = args.get(0); LIBC.execvp(exe, new StringArray(args.toArray(new String[args.size()]))); throw new IOException("Failed to exec '"+exe+"' "+LIBC.strerror(Native.getLastError())); }
/** * Run chmod via libc if we can, otherwise fall back to Ant. */ private static void _chmod(File f, int mask) throws IOException { if (Functions.isWindows()) return; // noop try { if(LIBC.chmod(f.getAbsolutePath(),mask)!=0) { throw new IOException("Failed to chmod "+f+" : "+LIBC.strerror(Native.getLastError())); } } catch(NoClassDefFoundError e) { // cf. https://groups.google.com/group/hudson-dev/browse_thread/thread/6d16c3e8ea0dbc9?hl=fr _chmodAnt(f, mask); } catch(UnsatisfiedLinkError e2) { // HUDSON-8155: use Ant's chmod task on non-GNU C systems _chmodAnt(f, mask); } }
public boolean isRoot() { return LIBC.geteuid()==0; }
for (int sz=512; sz < 65536; sz*=2) { Memory m = new Memory(sz); int r = LIBC.readlink(filename,m,new NativeLong(sz)); if (r<0) { int err = Native.getLastError(); if (err==22/*EINVAL --- but is this really portable?*/) return null; // this means it's not a symlink throw new IOException("Failed to readlink "+link+" error="+ err+" "+ LIBC.strerror(err));
@IgnoreJRERequirement private void process(File f) { if (f.isFile()) { if(Functions.isMustangOrAbove()) f.setExecutable(true, false); else { try { GNUCLibrary.LIBC.chmod(f.getAbsolutePath(),0755); } catch (LinkageError e) { // if JNA is unavailable, fall back. // we still prefer to try JNA first as PosixAPI supports even smaller platforms. PosixAPI.get().chmod(f.getAbsolutePath(),0755); } } } else { File[] kids = f.listFiles(); if (kids != null) { for (File kid : kids) { process(kid); } } } } }
if(LIBC.sysctl(new int[]{CTL_KERN,KERN_ARGMAX},2, argmaxRef.getPointer(), size, NULL, intByRef)!=0) throw new IOException("Failed to get kern.argmax: "+LIBC.strerror(Native.getLastError())); if(LIBC.sysctl(new int[]{CTL_KERN,KERN_PROCARGS2,pid},3, m, size, NULL, intByRef)!=0) throw new IOException("Failed to obtain ken.procargs2: "+LIBC.strerror(Native.getLastError()));
@Override public void restart() throws IOException, InterruptedException { Jenkins jenkins = Jenkins.getInstanceOrNull(); // guard against repeated concurrent calls to restart try { if (jenkins != null) { jenkins.cleanUp(); } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to clean up. Restart will continue.", e); } // close all files upon exec, except stdin, stdout, and stderr int sz = LIBC.getdtablesize(); for(int i=3; i<sz; i++) { int flags = LIBC.fcntl(i, F_GETFD); if(flags<0) continue; LIBC.fcntl(i, F_SETFD,flags| FD_CLOEXEC); } // exec to self String exe = args.get(0); LIBC.execvp(exe, new StringArray(args.toArray(new String[args.size()]))); throw new IOException("Failed to exec '"+exe+"' "+LIBC.strerror(Native.getLastError())); }
/** * Run chmod via libc if we can, otherwise fall back to Ant. */ private static void _chmod(File f, int mask) throws IOException { if (Functions.isWindows()) return; // noop try { if(LIBC.chmod(f.getAbsolutePath(),mask)!=0) { throw new IOException("Failed to chmod "+f+" : "+LIBC.strerror(Native.getLastError())); } } catch(NoClassDefFoundError e) { // cf. https://groups.google.com/group/hudson-dev/browse_thread/thread/6d16c3e8ea0dbc9?hl=fr _chmodAnt(f, mask); } catch(UnsatisfiedLinkError e2) { // HUDSON-8155: use Ant's chmod task on non-GNU C systems _chmodAnt(f, mask); } }
VirtualChannel start(TaskListener listener, String rootPassword) throws IOException, InterruptedException { final int uid = LIBC.geteuid(); if(uid==0) // already running as root return newLocalChannel(); String javaExe = System.getProperty("java.home") + "/bin/java"; File slaveJar = Which.jarFile(Launcher.class); ArgumentListBuilder args = new ArgumentListBuilder().add(javaExe); if(slaveJar.isFile()) args.add("-jar").add(slaveJar); else // in production code this never happens, but during debugging this is convenient args.add("-cp").add(slaveJar).add(hudson.remoting.Launcher.class.getName()); if(rootPassword==null) { // try sudo, in the hope that the user has the permission to do so without password return new LocalLauncher(listener).launchChannel( args.prepend(sudoExe()).toCommandArray(), listener.getLogger(), null, Collections.<String, String>emptyMap()); } else { // try sudo with the given password. Also run in pfexec so that we can elevate the privileges Process proc = sudoWithPass(args); return Channels.forProcess(args.toStringWithQuote(), Computer.threadPoolForRemoting, proc, listener.getLogger() ); } } }
@Override public boolean canWork() { try { if (File.pathSeparatorChar!=':') return false; // quick test to reject non-Unix without loading all the rest of the classes args = JavaVMArguments.current(); // go through the whole motion to make sure all the relevant classes are loaded now LIBC.getdtablesize(); int v = LIBC.fcntl(99999, F_GETFD); LIBC.fcntl(99999, F_SETFD, v); Daemon.getCurrentExecutable(); LIBC.execv("positively/no/such/executable", new StringArray(new String[]{"a","b","c"})); return true; } catch (UnsupportedOperationException e) { LOGGER.log(FINE, getClass()+" unsuitable", e); return false; } catch (LinkageError e) { LOGGER.log(FINE, getClass()+" unsuitable", e); return false; } catch (IOException e) { LOGGER.log(FINE, getClass()+" unsuitable", e); return false; } }
@Override public void run() { try { Thread.sleep(5000); // close all descriptors on exec except stdin,out,err int sz = LIBC.getdtablesize(); for(int i=3; i<sz; i++) { int flags = LIBC.fcntl(i, F_GETFD); if(flags<0) continue; LIBC.fcntl(i, F_SETFD,flags| FD_CLOEXEC); } // re-exec with the system property to indicate where to migrate the data to. // the 2nd phase is implemented in the migrate method. JavaVMArguments args = JavaVMArguments.current(); args.setSystemProperty(ZFSInstaller.class.getName()+".migrate",datasetName); Daemon.selfExec(args); } catch (InterruptedException | IOException e) { LOGGER.log(Level.SEVERE, "Restart failed",e); } } }.start();