From 32259aadda4d9460445e768008f73d239280e14e Mon Sep 17 00:00:00 2001 From: dokaptur Date: Tue, 9 Dec 2014 12:02:22 +0100 Subject: [PATCH 1/4] basic version 1 --- Makefile | 1 + src/stdbuf/libstdbuf.c | 7 ++ src/stdbuf/libstdbuf.h | 6 ++ src/stdbuf/libstdbuf.rs | 48 +++++++++ src/stdbuf/prepare_libs.sh | 9 ++ src/stdbuf/stdbuf.rs | 215 +++++++++++++++++++++++++++++++++++++ 6 files changed, 286 insertions(+) create mode 100644 src/stdbuf/libstdbuf.c create mode 100644 src/stdbuf/libstdbuf.h create mode 100644 src/stdbuf/libstdbuf.rs create mode 100755 src/stdbuf/prepare_libs.sh create mode 100644 src/stdbuf/stdbuf.rs diff --git a/Makefile b/Makefile index 158ff8f61..cc24773ba 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,7 @@ PROGS := \ seq \ shuf \ sort \ + stdbuf \ sum \ sync \ tac \ diff --git a/src/stdbuf/libstdbuf.c b/src/stdbuf/libstdbuf.c new file mode 100644 index 000000000..b7ee1370f --- /dev/null +++ b/src/stdbuf/libstdbuf.c @@ -0,0 +1,7 @@ +#include "libstdbuf.h" + +void __attribute ((constructor)) +stdbuf_init (void) +{ + stdbuf(); +} diff --git a/src/stdbuf/libstdbuf.h b/src/stdbuf/libstdbuf.h new file mode 100644 index 000000000..d8ae3c70a --- /dev/null +++ b/src/stdbuf/libstdbuf.h @@ -0,0 +1,6 @@ +#ifndef UUTILS_LIBSTDBUF_H +#define UUTILS_LIBSTDBUF_H + +void stdbuf(void); + +#endif diff --git a/src/stdbuf/libstdbuf.rs b/src/stdbuf/libstdbuf.rs new file mode 100644 index 000000000..3187ef55c --- /dev/null +++ b/src/stdbuf/libstdbuf.rs @@ -0,0 +1,48 @@ +#![crate_type = "dylib"] + +extern crate libc; +use libc::{c_int, size_t, c_char, FILE, _IOFBF, _IONBF, _IOLBF, setvbuf}; +use std::ptr; +use std::os; + +extern { + static stdin: *mut FILE; + static stdout: *mut FILE; + static stderr: *mut FILE; +} + +fn set_buffer(stream: *mut FILE, value: &str) { + let (mode, size): (c_int, size_t) = match value { + "0" => (_IONBF, 0 as size_t), + "L" => (_IOLBF, 0 as size_t), + input => { + let buff_size: uint = match from_str(input) { + Some(num) => num, + None => panic!("incorrect size of buffer!") + }; + (_IOFBF, buff_size as size_t) + } + }; + let mut res: c_int; + unsafe { + let buffer: *mut c_char = ptr::null_mut(); + assert!(buffer.is_null()); + res = libc::setvbuf(stream, buffer, mode, size); + } + if res != 0 { + panic!("error while calling setvbuf!"); + } +} + +#[no_mangle] +pub extern fn stdbuf() { + if let Some(val) = os::getenv("_STDBUF_E") { + set_buffer(stderr, val.as_slice()); + } + if let Some(val) = os::getenv("_STDBUF_I") { + set_buffer(stdin, val.as_slice()); + } + if let Some(val) = os::getenv("_STDBUF_O") { + set_buffer(stdout, val.as_slice()); + } +} diff --git a/src/stdbuf/prepare_libs.sh b/src/stdbuf/prepare_libs.sh new file mode 100755 index 000000000..bc0869123 --- /dev/null +++ b/src/stdbuf/prepare_libs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +cd $(dirname $0) +rustc libstdbuf.rs +gcc -c -Wall -Werror -fpic libstdbuf.c -L. -llibstdbuf.so +gcc -shared -o libstdbuf.so libstdbuf.o +mv *.so ../../build/ +rm *.o +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$PWD"/../../build diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs new file mode 100644 index 000000000..548e23351 --- /dev/null +++ b/src/stdbuf/stdbuf.rs @@ -0,0 +1,215 @@ +#![crate_name = "stdbuf"] + +/* +* This file is part of the uutils coreutils package. +* +* (c) Dorota Kapturkiewicz +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ +#![feature(macro_rules)] + +extern crate getopts; +extern crate libc; +use getopts::{optopt, optflag, getopts, usage, Matches, OptGroup}; +use std::io::process::{Command, StdioContainer}; +use std::iter::range_inclusive; +use std::num::Int; + +#[path = "../common/util.rs"] +mod util; + +static NAME: &'static str = "stdbuf"; +static VERSION: &'static str = "1.0.0"; +static LIBSTDBUF_PATH: &'static str = "liblibstdbuf.so libstdbuf.so"; + +#[deriving(Show)] +enum BufferType { + Default, + Line, + Size(u64) +} + +#[deriving(Show)] +struct ProgramOptions { + stdin: BufferType, + stdout: BufferType, + stderr: BufferType, +} + +enum ErrMsg { + Retry, + Fatal +} + +enum OkMsg { + Buffering, + Help, + Version +} + +fn print_version() { + println!("{} version {}", NAME, VERSION); +} + +fn print_usage(opts: &[OptGroup]) { + let brief = + "Usage: stdbuf OPTION... COMMAND\n \ + Run COMMAND, with modified buffering operations for its standard streams\n \ + Mandatory arguments to long options are mandatory for short options too."; + let explanation = + "If MODE is 'L' the corresponding stream will be line buffered.\n \ + This option is invalid with standard input.\n\n \ + If MODE is '0' the corresponding stream will be unbuffered.\n\n \ + Otherwise MODE is a number which may be followed by one of the following:\n\n \ + KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n \ + In this case the corresponding stream will be fully buffered with the buffer size set to MODE bytes.\n\n \ + NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for e.g.) then that will override \ + corresponding settings changed by 'stdbuf'.\n \ + Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O, \ + and are thus unaffected by 'stdbuf' settings.\n"; + println!("{}\n{}", getopts::usage(brief, opts), explanation); +} + +fn parse_size(size: &str) -> Option { + let ext = size.trim_left_chars(|c: char| c.is_digit(10)); + let num = size.trim_right_chars(|c: char| c.is_alphabetic()); + let mut recovered = num.to_string(); + recovered.push_str(ext); + if recovered.as_slice() != size { + return None; + } + let buf_size: u64 = match from_str(num) { + Some(m) => m, + None => return None, + }; + let (power, base): (uint, u64) = match ext { + "" => (0, 0), + "KB" => (1, 1024), + "K" => (1, 1000), + "MB" => (2, 1024), + "M" => (2, 1000), + "GB" => (3, 1024), + "G" => (3, 1000), + "TB" => (4, 1024), + "T" => (4, 1000), + "PB" => (5, 1024), + "P" => (5, 1000), + "EB" => (6, 1024), + "E" => (6, 1000), + "ZB" => (7, 1024), + "Z" => (7, 1000), + "YB" => (8, 1024), + "Y" => (8, 1000), + _ => return None, + }; + Some(buf_size * base.pow(power)) +} + +fn check_option(matches: &Matches, name: &str, modified: &mut bool) -> Option { + match matches.opt_str(name) { + Some(value) => { + *modified = true; + match value.as_slice() { + "L" => { + if name == "input" { + show_info!("stdbuf: line buffering stdin is meaningless"); + None + } else { + Some(BufferType::Line) + } + }, + x => { + let size = match parse_size(x) { + Some(m) => m, + None => { show_error!("Invalid mode {}", x); return None } + }; + Some(BufferType::Size(size)) + }, + } + }, + None => Some(BufferType::Default), + } +} + +fn parse_options(args: &[String], options: &mut ProgramOptions, optgrps: &[OptGroup]) -> Result { + let matches = match getopts(args, optgrps) { + Ok(m) => m, + Err(_) => return Err(ErrMsg::Retry) + }; + if matches.opt_present("help") { + return Ok(OkMsg::Help); + } + if matches.opt_present("version") { + return Ok(OkMsg::Version); + } + let mut modified = false; + options.stdin = try!(check_option(&matches, "input", &mut modified).ok_or(ErrMsg::Fatal)); + options.stdout = try!(check_option(&matches, "output", &mut modified).ok_or(ErrMsg::Fatal)); + options.stderr = try!(check_option(&matches, "error", &mut modified).ok_or(ErrMsg::Fatal)); + + if matches.free.len() != 1 { + return Err(ErrMsg::Retry); + } + if !modified { + show_error!("stdbuf: you must specify a buffering mode option"); + return Err(ErrMsg::Fatal); + } + Ok(OkMsg::Buffering) +} + +fn set_command_env(command: &mut Command, buffer_name: &str, buffer_type: BufferType) { + match buffer_type { + BufferType::Size(m) => { command.env(buffer_name, m.to_string()); }, + BufferType::Line => { command.env(buffer_name, "L"); }, + BufferType::Default => {}, + } +} + + +pub fn uumain(args: Vec) -> int { + let optgrps = [ + optopt("i", "input", "adjust standard input stream buffering", "MODE"), + optopt("o", "output", "adjust standard output stream buffering", "MODE"), + optopt("e", "error", "adjust standard error stream buffering", "MODE"), + optflag("", "help", "display this help and exit"), + optflag("", "version", "output version information and exit"), + ]; + let mut options = ProgramOptions {stdin: BufferType::Default, stdout: BufferType::Default, stderr: BufferType::Default}; + let mut command_idx = -1; + for i in range_inclusive(1, args.len()) { + match parse_options(args.slice(1, i), &mut options, &optgrps) { + Ok(OkMsg::Buffering) => { + command_idx = i-1; + break; + }, + Ok(OkMsg::Help) => { + print_usage(&optgrps); + return 0; + }, + Ok(OkMsg::Version) => { + print_version(); + return 0; + }, + Err(ErrMsg::Fatal) => break, + Err(ErrMsg::Retry) => continue, + } + }; + if command_idx == -1 { + crash!(125, "Invalid options\nTry 'stdbuf --help' for more information."); + } + let ref command_name = args[command_idx]; + let mut command = Command::new(command_name); + command.args(args.slice_from(command_idx+1)).env("LD_PRELOAD", LIBSTDBUF_PATH); + command.stdin(StdioContainer::InheritFd(0)).stdout(StdioContainer::InheritFd(1)).stderr(StdioContainer::InheritFd(2)); + set_command_env(&mut command, "_STDBUF_I", options.stdin); + set_command_env(&mut command, "_STDBUF_O", options.stdout); + set_command_env(&mut command, "_STDBUF_E", options.stderr); + match command.spawn() { + Ok(_) => {}, + Err(e) => crash!(1, "failed to execute process: {}", e), + }; + 0 +} + From 563c9ab34eae7b88c4d1796101e17bbc8d438021 Mon Sep 17 00:00:00 2001 From: dokaptur Date: Sun, 14 Dec 2014 01:20:49 +0100 Subject: [PATCH 2/4] preloading improvement --- src/stdbuf/libstdbuf.rs | 13 ++++++++++--- src/stdbuf/prepare_libs.sh | 6 +++--- src/stdbuf/stdbuf.rs | 35 +++++++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/stdbuf/libstdbuf.rs b/src/stdbuf/libstdbuf.rs index 3187ef55c..f10775bb1 100644 --- a/src/stdbuf/libstdbuf.rs +++ b/src/stdbuf/libstdbuf.rs @@ -1,16 +1,23 @@ -#![crate_type = "dylib"] +#![crate_name = "libstdbuf"] +#![crate_type = "staticlib"] +#![feature(macro_rules)] extern crate libc; use libc::{c_int, size_t, c_char, FILE, _IOFBF, _IONBF, _IOLBF, setvbuf}; use std::ptr; use std::os; +#[path = "../common/util.rs"] +mod util; + extern { static stdin: *mut FILE; static stdout: *mut FILE; static stderr: *mut FILE; } +static NAME: &'static str = "libstdbuf"; + fn set_buffer(stream: *mut FILE, value: &str) { let (mode, size): (c_int, size_t) = match value { "0" => (_IONBF, 0 as size_t), @@ -18,7 +25,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { input => { let buff_size: uint = match from_str(input) { Some(num) => num, - None => panic!("incorrect size of buffer!") + None => crash!(1, "incorrect size of buffer!") }; (_IOFBF, buff_size as size_t) } @@ -30,7 +37,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - panic!("error while calling setvbuf!"); + crash!(res, "error while calling setvbuf!"); } } diff --git a/src/stdbuf/prepare_libs.sh b/src/stdbuf/prepare_libs.sh index bc0869123..6be6d920d 100755 --- a/src/stdbuf/prepare_libs.sh +++ b/src/stdbuf/prepare_libs.sh @@ -2,8 +2,8 @@ cd $(dirname $0) rustc libstdbuf.rs -gcc -c -Wall -Werror -fpic libstdbuf.c -L. -llibstdbuf.so -gcc -shared -o libstdbuf.so libstdbuf.o +gcc -c -Wall -Werror -fpic libstdbuf.c -L. -llibstdbuf.a +gcc -shared -o libstdbuf.so -Wl,--whole-archive liblibstdbuf.a -Wl,--no-whole-archive libstdbuf.o -lpthread mv *.so ../../build/ rm *.o -export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$PWD"/../../build +rm *.a diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs index 548e23351..e01a8c60f 100644 --- a/src/stdbuf/stdbuf.rs +++ b/src/stdbuf/stdbuf.rs @@ -16,22 +16,21 @@ use getopts::{optopt, optflag, getopts, usage, Matches, OptGroup}; use std::io::process::{Command, StdioContainer}; use std::iter::range_inclusive; use std::num::Int; +use std::os; #[path = "../common/util.rs"] mod util; static NAME: &'static str = "stdbuf"; static VERSION: &'static str = "1.0.0"; -static LIBSTDBUF_PATH: &'static str = "liblibstdbuf.so libstdbuf.so"; +static LIBSTDBUF: &'static str = "libstdbuf.so"; -#[deriving(Show)] enum BufferType { Default, Line, Size(u64) } -#[deriving(Show)] struct ProgramOptions { stdin: BufferType, stdout: BufferType, @@ -49,6 +48,22 @@ enum OkMsg { Version } +#[cfg(target_os = "linux")] +fn preload_env() -> &'static str { + "LD_PRELOAD" +} + +#[cfg(target_os = "macos")] +fn preload_env() -> &'static str { + "DYLD_INSERT_LIBRARIES" +} + +#[cfg(not(any(target_os = "linux", target_os = "macos")))] +fn preload_env() -> &'static str { + crash!(1, "Command not supported for this operating system!") +} + + fn print_version() { println!("{} version {}", NAME, VERSION); } @@ -181,7 +196,7 @@ pub fn uumain(args: Vec) -> int { for i in range_inclusive(1, args.len()) { match parse_options(args.slice(1, i), &mut options, &optgrps) { Ok(OkMsg::Buffering) => { - command_idx = i-1; + command_idx = i - 1; break; }, Ok(OkMsg::Help) => { @@ -201,7 +216,16 @@ pub fn uumain(args: Vec) -> int { } let ref command_name = args[command_idx]; let mut command = Command::new(command_name); - command.args(args.slice_from(command_idx+1)).env("LD_PRELOAD", LIBSTDBUF_PATH); + let mut path = match os::self_exe_path() { + Some(exe_path) => exe_path, + None => crash!(1, "Impossible to fetch the path of this executable.") + }; + path.push(LIBSTDBUF); + let libstdbuf = match path.as_str() { + Some(s) => s, + None => crash!(1, "Error while converting path.") + }; + command.args(args.slice_from(command_idx+1)).env(preload_env(), libstdbuf); command.stdin(StdioContainer::InheritFd(0)).stdout(StdioContainer::InheritFd(1)).stderr(StdioContainer::InheritFd(2)); set_command_env(&mut command, "_STDBUF_I", options.stdin); set_command_env(&mut command, "_STDBUF_O", options.stdout); @@ -212,4 +236,3 @@ pub fn uumain(args: Vec) -> int { }; 0 } - From b71df2fd783bab3b4ea23112b09bb9023dcb4cdb Mon Sep 17 00:00:00 2001 From: dokaptur Date: Tue, 30 Dec 2014 20:11:36 +0100 Subject: [PATCH 3/4] prepare_libs in Makefile --- Makefile | 45 +++++++++++++++++++++++++---- src/stdbuf/libstdbuf.rs | 5 ++-- src/stdbuf/prepare_libs.sh | 9 ------ src/stdbuf/stdbuf.rs | 58 +++++++++++++++++++++++--------------- 4 files changed, 78 insertions(+), 39 deletions(-) delete mode 100755 src/stdbuf/prepare_libs.sh diff --git a/Makefile b/Makefile index cc24773ba..bc1da52e6 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,15 @@ ENABLE_LTO ?= n ENABLE_STRIP ?= n # Binaries -RUSTC ?= rustc -CARGO ?= cargo -RM := rm +RUSTC ?= rustc +CARGO ?= cargo +CC ?= gcc +RM := rm # Install directories -PREFIX ?= /usr/local -BINDIR ?= /bin +PREFIX ?= /usr/local +BINDIR ?= /bin +LIBDIR ?= /lib # This won't support any directory with spaces in its name, but you can just # make a symlink without spaces that points to the directory. @@ -75,7 +77,6 @@ PROGS := \ seq \ shuf \ sort \ - stdbuf \ sum \ sync \ tac \ @@ -106,6 +107,7 @@ UNIX_PROGS := \ mkfifo \ nice \ nohup \ + stdbuf \ timeout \ tty \ uname \ @@ -137,6 +139,22 @@ INSTALL ?= $(EXES) INSTALLEES := \ $(filter $(INSTALL),$(filter-out $(DONT_INSTALL),$(EXES) uutils)) +# Shared library extension +SYSTEM := $(shell uname) +DYLIB_EXT := +ifeq ($(SYSTEM),Linux) + DYLIB_EXT := so +endif +ifeq ($(SYSTEM),Darwin) + DYLIB_EXT := dylib +endif + +# Libaries to install +LIBS := +ifneq (,$(findstring stdbuf, $(INSTALLEES))) +LIBS += libstdbuf.$(DYLIB_EXT) +endif + # Programs with usable tests TEST_PROGS := \ cat \ @@ -225,6 +243,16 @@ $(BUILDDIR)/uutils: $(SRCDIR)/uutils/uutils.rs $(BUILDDIR)/mkuutils $(RLIB_PATHS $(BUILDDIR)/mkuutils $(BUILDDIR)/gen/uutils.rs $(EXES) $(RUSTC) $(RUSTCBINFLAGS) --extern test=$(BUILDDIR)/libtest.rlib --emit link,dep-info $(BUILDDIR)/gen/uutils.rs --out-dir $(BUILDDIR) $(if $(ENABLE_STRIP),strip $@) + +# Library for stdbuf +$(BUILDIR)/libstdbuf.$(DYLIB_EXT): $(SRCDIR)/stdbuf/libstdbuf.rs $(SRCDIR)/stdbuf/libstdbuf.c $(SRCDIR)/stdbuf/libstdbuf.h | $(BUILDDIR) + cd $(SRCDIR)/stdbuf && \ + $(RUSTC) libstdbuf.rs && \ + $(CC) -c -Wall -Werror -fpic libstdbuf.c -L. -llibstdbuf.a && \ + $(CC) -shared -o libstdbuf.$(DYLIB_EXT) -Wl,--whole-archive liblibstdbuf.a -Wl,--no-whole-archive libstdbuf.o -lpthread && \ + mv *.so $(BUILDDIR) && $(RM) *.o && $(RM) *.a + +$(BUILDDIR)/stdbuf: $(BUILDIR)/libstdbuf.$(DYLIB_EXT) # Dependencies $(BUILDDIR)/.rust-crypto: | $(BUILDDIR) @@ -278,6 +306,10 @@ install: $(addprefix $(BUILDDIR)/,$(INSTALLEES)) for prog in $(INSTALLEES); do \ install $(BUILDDIR)/$$prog $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX)$$prog; \ done + mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR) + for lib in $(LIBS); do \ + install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \ + done # TODO: figure out if there is way for prefixes to work with the symlinks install-multicall: $(BUILDDIR)/uutils @@ -290,6 +322,7 @@ install-multicall: $(BUILDDIR)/uutils uninstall: rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX),$(PROGS)) + rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS)) uninstall-multicall: rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/,$(PROGS) $(PROG_PREFIX)uutils) diff --git a/src/stdbuf/libstdbuf.rs b/src/stdbuf/libstdbuf.rs index f10775bb1..4c14fab0f 100644 --- a/src/stdbuf/libstdbuf.rs +++ b/src/stdbuf/libstdbuf.rs @@ -1,6 +1,6 @@ #![crate_name = "libstdbuf"] #![crate_type = "staticlib"] -#![feature(macro_rules)] +#![allow(unstable)] extern crate libc; use libc::{c_int, size_t, c_char, FILE, _IOFBF, _IONBF, _IOLBF, setvbuf}; @@ -8,6 +8,7 @@ use std::ptr; use std::os; #[path = "../common/util.rs"] +#[macro_use] mod util; extern { @@ -23,7 +24,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { "0" => (_IONBF, 0 as size_t), "L" => (_IOLBF, 0 as size_t), input => { - let buff_size: uint = match from_str(input) { + let buff_size: usize = match input.parse() { Some(num) => num, None => crash!(1, "incorrect size of buffer!") }; diff --git a/src/stdbuf/prepare_libs.sh b/src/stdbuf/prepare_libs.sh deleted file mode 100755 index 6be6d920d..000000000 --- a/src/stdbuf/prepare_libs.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd $(dirname $0) -rustc libstdbuf.rs -gcc -c -Wall -Werror -fpic libstdbuf.c -L. -llibstdbuf.a -gcc -shared -o libstdbuf.so -Wl,--whole-archive liblibstdbuf.a -Wl,--no-whole-archive libstdbuf.o -lpthread -mv *.so ../../build/ -rm *.o -rm *.a diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs index e01a8c60f..3c7f8e8aa 100644 --- a/src/stdbuf/stdbuf.rs +++ b/src/stdbuf/stdbuf.rs @@ -1,4 +1,5 @@ #![crate_name = "stdbuf"] +#![allow(unstable)] /* * This file is part of the uutils coreutils package. @@ -8,22 +9,23 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -#![feature(macro_rules)] extern crate getopts; extern crate libc; use getopts::{optopt, optflag, getopts, usage, Matches, OptGroup}; use std::io::process::{Command, StdioContainer}; +use std::io::fs::PathExtensions; use std::iter::range_inclusive; use std::num::Int; use std::os; #[path = "../common/util.rs"] +#[macro_use] mod util; static NAME: &'static str = "stdbuf"; static VERSION: &'static str = "1.0.0"; -static LIBSTDBUF: &'static str = "libstdbuf.so"; +static LIBSTDBUF: &'static str = "libstdbuf"; enum BufferType { Default, @@ -49,17 +51,17 @@ enum OkMsg { } #[cfg(target_os = "linux")] -fn preload_env() -> &'static str { - "LD_PRELOAD" +fn preload_strings() -> (&'static str, &'static str) { + ("LD_PRELOAD", ".so") } #[cfg(target_os = "macos")] -fn preload_env() -> &'static str { - "DYLD_INSERT_LIBRARIES" +fn preload_strings() -> (&'static str, &'static str) { + ("DYLD_INSERT_LIBRARIES", ".dyl") } #[cfg(not(any(target_os = "linux", target_os = "macos")))] -fn preload_env() -> &'static str { +fn preload_strings() -> (&'static str, &'static str) { crash!(1, "Command not supported for this operating system!") } @@ -88,18 +90,18 @@ fn print_usage(opts: &[OptGroup]) { } fn parse_size(size: &str) -> Option { - let ext = size.trim_left_chars(|c: char| c.is_digit(10)); - let num = size.trim_right_chars(|c: char| c.is_alphabetic()); + let ext = size.trim_left_matches(|&: c: char| c.is_digit(10)); + let num = size.trim_right_matches(|&: c: char| c.is_alphabetic()); let mut recovered = num.to_string(); recovered.push_str(ext); if recovered.as_slice() != size { return None; } - let buf_size: u64 = match from_str(num) { + let buf_size: u64 = match num.parse() { Some(m) => m, None => return None, }; - let (power, base): (uint, u64) = match ext { + let (power, base): (usize, u64) = match ext { "" => (0, 0), "KB" => (1, 1024), "K" => (1, 1000), @@ -182,8 +184,28 @@ fn set_command_env(command: &mut Command, buffer_name: &str, buffer_type: Buffer } } +fn get_preload_env() -> (String, String) { + let (preload, extension) = preload_strings(); + let mut libstdbuf = LIBSTDBUF.to_string(); + libstdbuf.push_str(extension); + // First search for library in directory of executable. + let mut path = match os::self_exe_path() { + Some(exe_path) => exe_path, + None => crash!(1, "Impossible to fetch the path of this executable.") + }; + path.push(libstdbuf.as_slice()); + if path.exists() { + match path.as_str() { + Some(s) => { return (preload.to_string(), s.to_string()); }, + None => crash!(1, "Error while converting path.") + }; + } + // We assume library is in LD_LIBRARY_PATH/ DYLD_LIBRARY_PATH. + (preload.to_string(), libstdbuf) +} -pub fn uumain(args: Vec) -> int { + +pub fn uumain(args: Vec) -> isize { let optgrps = [ optopt("i", "input", "adjust standard input stream buffering", "MODE"), optopt("o", "output", "adjust standard output stream buffering", "MODE"), @@ -216,16 +238,8 @@ pub fn uumain(args: Vec) -> int { } let ref command_name = args[command_idx]; let mut command = Command::new(command_name); - let mut path = match os::self_exe_path() { - Some(exe_path) => exe_path, - None => crash!(1, "Impossible to fetch the path of this executable.") - }; - path.push(LIBSTDBUF); - let libstdbuf = match path.as_str() { - Some(s) => s, - None => crash!(1, "Error while converting path.") - }; - command.args(args.slice_from(command_idx+1)).env(preload_env(), libstdbuf); + let (preload_env, libstdbuf) = get_preload_env(); + command.args(args.slice_from(command_idx+1)).env(preload_env.as_slice(), libstdbuf.as_slice()); command.stdin(StdioContainer::InheritFd(0)).stdout(StdioContainer::InheritFd(1)).stderr(StdioContainer::InheritFd(2)); set_command_env(&mut command, "_STDBUF_I", options.stdin); set_command_env(&mut command, "_STDBUF_O", options.stdout); From ec4182fcf1541d2b3fc3fc60740682127e11949d Mon Sep 17 00:00:00 2001 From: dokaptur Date: Fri, 23 Jan 2015 17:35:54 +0100 Subject: [PATCH 4/4] stdbuf - install multicall --- Makefile | 25 +++++++++++++++---------- src/stdbuf/stdbuf.rs | 13 ++++++------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index bc1da52e6..0d1c44bea 100644 --- a/Makefile +++ b/Makefile @@ -3,15 +3,15 @@ ENABLE_LTO ?= n ENABLE_STRIP ?= n # Binaries -RUSTC ?= rustc -CARGO ?= cargo -CC ?= gcc -RM := rm +RUSTC ?= rustc +CARGO ?= cargo +CC ?= gcc +RM := rm # Install directories -PREFIX ?= /usr/local -BINDIR ?= /bin -LIBDIR ?= /lib +PREFIX ?= /usr/local +BINDIR ?= /bin +LIBDIR ?= /lib # This won't support any directory with spaces in its name, but you can just # make a symlink without spaces that points to the directory. @@ -143,16 +143,16 @@ INSTALLEES := \ SYSTEM := $(shell uname) DYLIB_EXT := ifeq ($(SYSTEM),Linux) - DYLIB_EXT := so + DYLIB_EXT := .so endif ifeq ($(SYSTEM),Darwin) - DYLIB_EXT := dylib + DYLIB_EXT := .dylib endif # Libaries to install LIBS := ifneq (,$(findstring stdbuf, $(INSTALLEES))) -LIBS += libstdbuf.$(DYLIB_EXT) +LIBS += libstdbuf$(DYLIB_EXT) endif # Programs with usable tests @@ -319,6 +319,10 @@ install-multicall: $(BUILDDIR)/uutils for prog in $(INSTALLEES); do \ ln -s $(PROG_PREFIX)uutils $$prog; \ done + mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR) + for lib in $(LIBS); do \ + install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \ + done uninstall: rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX),$(PROGS)) @@ -326,6 +330,7 @@ uninstall: uninstall-multicall: rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/,$(PROGS) $(PROG_PREFIX)uutils) + rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS)) # Test under the busybox testsuite $(BUILDDIR)/busybox: $(BUILDDIR)/uutils diff --git a/src/stdbuf/stdbuf.rs b/src/stdbuf/stdbuf.rs index 3c7f8e8aa..100cc2641 100644 --- a/src/stdbuf/stdbuf.rs +++ b/src/stdbuf/stdbuf.rs @@ -57,7 +57,7 @@ fn preload_strings() -> (&'static str, &'static str) { #[cfg(target_os = "macos")] fn preload_strings() -> (&'static str, &'static str) { - ("DYLD_INSERT_LIBRARIES", ".dyl") + ("DYLD_INSERT_LIBRARIES", ".dylib") } #[cfg(not(any(target_os = "linux", target_os = "macos")))] @@ -216,7 +216,7 @@ pub fn uumain(args: Vec) -> isize { let mut options = ProgramOptions {stdin: BufferType::Default, stdout: BufferType::Default, stderr: BufferType::Default}; let mut command_idx = -1; for i in range_inclusive(1, args.len()) { - match parse_options(args.slice(1, i), &mut options, &optgrps) { + match parse_options(&args[1 .. i], &mut options, &optgrps) { Ok(OkMsg::Buffering) => { command_idx = i - 1; break; @@ -239,14 +239,13 @@ pub fn uumain(args: Vec) -> isize { let ref command_name = args[command_idx]; let mut command = Command::new(command_name); let (preload_env, libstdbuf) = get_preload_env(); - command.args(args.slice_from(command_idx+1)).env(preload_env.as_slice(), libstdbuf.as_slice()); + command.args(&args[command_idx + 1 ..]).env(preload_env.as_slice(), libstdbuf.as_slice()); command.stdin(StdioContainer::InheritFd(0)).stdout(StdioContainer::InheritFd(1)).stderr(StdioContainer::InheritFd(2)); set_command_env(&mut command, "_STDBUF_I", options.stdin); set_command_env(&mut command, "_STDBUF_O", options.stdout); set_command_env(&mut command, "_STDBUF_E", options.stderr); - match command.spawn() { - Ok(_) => {}, - Err(e) => crash!(1, "failed to execute process: {}", e), - }; + if let Err(e) = command.spawn() { + crash!(1, "failed to execute process: {}", e); + } 0 }