diff --git a/extra/dist/tarantoolctl b/extra/dist/tarantoolctl
index e79050ecba676c9bd08ee0d6ac70a46db2bdf882..0011525a0c02788d581887d80fc58f36fad962ac 100755
--- a/extra/dist/tarantoolctl
+++ b/extra/dist/tarantoolctl
@@ -106,29 +106,6 @@ local fiber = require 'fiber'
 
 ffi.cdef[[ int kill(int pid, int sig); ]]
 
-local config_file
-local usermode = true
-
-if os.getenv('HOME') then
-    config_file = os.getenv('HOME') .. '/.config/tarantool/tarantool'
-end
-
-if not fio.stat(config_file) then
-    usermode = false
-    local config_list = {
-        '/etc/sysconfig/tarantool',
-        '/etc/default/tarantool',
-        '/usr/local/etc/tarantool/tarantool',
-    }
-
-    for _, c in pairs(config_list) do
-        if fio.stat(c) then
-            config_file = c
-            break
-        end
-    end
-end
-
 local available_commands = {
     'start',
     'stop',
@@ -139,14 +116,41 @@ local available_commands = {
     'reload'
 }
 
+--
+-- true if we're running in HOME directory of a user
+--
+local usermode
+--
+-- a file with system-wide settings
+--
+local default_file
+--
+-- instance name
+--
+local instance_name
+--
+--
+--
+local instance_path
+--
+-- console socket
+--
+local console_sock
+
+--
+-- print usage and exit
+--
+
 local function usage()
     log.error("Usage: %s {%s} instance_name",
         arg[0], table.concat(available_commands, '|'))
-    log.error("Config file: %s", config_file)
+    log.error("Config file: %s", default_file)
     os.exit(1)
 end
 
+--
 -- shift argv to remove 'tarantoolctl' from arg[0]
+--
 local function shift_argv(arg, argno, argcount)
     for i = argno, 128 do
         arg[i] = arg[i + argcount]
@@ -156,80 +160,123 @@ local function shift_argv(arg, argno, argcount)
     end
 end
 
-local cmd = arg[1]
-
-local valid_cmd = false
-for _, vcmd in pairs(available_commands) do
-    if cmd == vcmd then
-        valid_cmd = true
-        break
+--
+-- Check if the requested action is among
+-- supported ones, and return it in this case
+-- Otherwise print help and exit.
+--
+local function check_cmd(cmd)
+    for _, vcmd in pairs(available_commands) do
+        if cmd == vcmd then
+            return cmd
+        end
     end
-end
-
-if not valid_cmd then
     usage()
 end
 
-local instance
-if arg[2] == nil then
-    local istat = fio.lstat(arg[0])
-    if istat == nil then
-        log.error("Can't stat %s: %s", arg[0], errno.strerror())
-        os.exit(1)
+--
+-- Find if we're running under a user, and this
+-- user has a default file in his home directory.
+-- If present, use it. Otherwise assume a system-
+-- wide default. If it's missing, it's OK as well.
+--
+local function find_default_file()
+    if os.getenv('HOME') then
+        local c = os.getenv('HOME') .. '/.config/tarantool/tarantool'
+        if fio.stat(c) then
+            usermode = true
+            return c
+        end
     end
-    if not istat:is_link() then
-        usage()
+    --
+    -- no user-level defaults, use a system-wide one
+    --
+    usermode = false
+    local config_list = {
+        '/etc/sysconfig/tarantool',
+        '/etc/default/tarantool',
+        '/usr/local/etc/tarantool/tarantool',
+    }
+    for _, c in pairs(config_list) do
+        if fio.stat(c) then
+            return c
+        end
     end
-    instance = fio.basename(arg[0], '.lua')
-    arg[2] = instance
-else
-    instance = fio.basename(arg[2], '.lua')
+    -- It's OK if there is no default file -
+    --  load_default_file() will assume some defaults
+    return nil
 end
 
-shift_argv(arg, 0, 2)
-
-local instance_lua = nil
-
-
-dofile(config_file)
-if instance_dir then
-    instance_lua = fio.pathjoin(instance_dir, instance .. '.lua')
-    if fio.stat(instance_lua) then
-        log.info('Found %s.lua in %s', instance, instance_dir)
+--
+-- System-wide default file may be missing, this is OK,
+-- we'll assume built-in defaults
+--
+function load_default_file(default_file)
+    if default_file then
+        dofile(default_file)
+    end
+    if default_cfg == nil then
+        default_cfg = {}
+    end
+    local d = default_cfg
+
+    d.pid_file   = d.pid_file and d.pid_file or "/var/run/tarantool"
+    d.wal_dir    = d.wal_dir  and d.wal_dir or "/var/lib/tarantool"
+    d.snap_dir   = d.snap_dir and d.snap_dir or "/var/lib/tarantool"
+    d.logger     = d.logger   and d.logger or "/var/log/tarantool"
+    d.sophia_dir = d.sophia_dir and d.sophia_dir or "/var/lib/tarantool"
+
+    d.pid_file   = fio.pathjoin(d.pid_file, instance_name .. '.pid')
+    d.wal_dir    = fio.pathjoin(d.wal_dir, instance_name)
+    d.snap_dir   = fio.pathjoin(d.snap_dir, instance_name)
+    d.sophia_dir = fio.pathjoin(d.sophia_dir, instance_name)
+    d.logger     = fio.pathjoin(d.logger, instance_name .. '.log')
+
+    if not usermode then
+        -- change user name only if not running locally
+        d.username = d.username and d.username or "tarantool"
+        --
+        -- instance_dir must be set in the defaults file,
+        -- but don't try to set it to the  global instance dir
+        -- if the user-local defaults file is in use
+        --
+        if not instance_dir then
+            instance_dir = '/etc/tarantool/instances.enabled'
+        end
     end
-end
-instance_dir = nil
-instance_lua = nil
 
-if default_cfg == nil then
-    default_cfg = {}
-end
+    if instance_dir == nil then
+        log.error('Instance directory (instance_dir) is not set in %s', default_file)
+        os.exit(-1)
+    end
 
-if instance_dir == nil then
-    instance_dir = '/etc/tarantool/instances.enabled'
-    instance_lua = fio.pathjoin(instance_dir, instance .. '.lua')
+    if not fio.stat(instance_dir) then
+        log.error('Instance directory %s does not exist', instance_dir)
+        os.exit(-1)
+    end
 end
 
-default_cfg.pid_file   = default_cfg.pid_file and default_cfg.pid_file or "/var/run/tarantool"
-default_cfg.wal_dir    = default_cfg.wal_dir and default_cfg.wal_dir or "/var/lib/tarantool"
-default_cfg.snap_dir   = default_cfg.snap_dir and default_cfg.snap_dir or "/var/lib/tarantool"
-default_cfg.sophia_dir = default_cfg.sophia_dir and default_cfg.sophia_dir or "/var/lib/tarantool"
-default_cfg.logger     = default_cfg.logger and default_cfg.logger or "/var/log/tarantool"
--- change user name only if not running locally
-if not usermode then
-    default_cfg.username = default_cfg.username and default_cfg.username or "tarantool"
+--
+-- In case there is no explicit instance name,
+-- check whether arg[0] is a symlink. In that
+-- case, the name of the symlink is the instance
+-- name.
+--
+local function find_instance_name(arg0, arg2)
+    if arg2 ~= nil then
+        return fio.basename(arg2, '.lua')
+    end
+    local istat = fio.lstat(arg0)
+    if istat == nil then
+        log.error("Can't stat %s: %s", arg0, errno.strerror())
+        os.exit(1)
+    end
+    if not istat:is_link() then
+        usage()
+    end
+    return fio.basename(arg0, '.lua')
 end
 
--- create  a path to the control socket (admin console)
-local console_sock = fio.pathjoin(default_cfg.pid_file, instance .. '.control')
-
-default_cfg.pid_file   = fio.pathjoin(default_cfg.pid_file, instance .. '.pid')
-default_cfg.wal_dir    = fio.pathjoin(default_cfg.wal_dir, instance)
-default_cfg.snap_dir   = fio.pathjoin(default_cfg.snap_dir, instance)
-default_cfg.sophia_dir = fio.pathjoin(default_cfg.sophia_dir, instance, 'sophia')
-default_cfg.logger     = fio.pathjoin(default_cfg.logger, instance .. '.log')
-
-local instance_lua = fio.pathjoin(instance_dir, instance .. '.lua')
 
 local function mkdir(dirname)
     log.info("mkdir %s", dirname)
@@ -269,30 +316,26 @@ function mk_default_dirs(cfg)
     end
 end
 
-local force_cfg = {
-    pid_file    = default_cfg.pid_file,
-    username    = default_cfg.username,
-    background  = true,
-    custom_proc_title = instance
-}
-
 local orig_cfg = box.cfg
-wrapper_cfg = function(cfg)
-
-    for i, v in pairs(force_cfg) do
-        cfg[i] = v
-    end
 
+local function wrapper_cfg(cfg)
     for i, v in pairs(default_cfg) do
         if cfg[i] == nil then
             cfg[i] = v
         end
     end
+    --
+    -- force these startup options
+    --
+    cfg.pid_file = default_cfg.pid_file
+    cfg.username = default_cfg.username
+    cfg.background = true
+    cfg.custom_proc_title = instance_name
 
     mk_default_dirs(cfg)
     local res = orig_cfg(cfg)
 
-    require('fiber').name(instance)
+    require('fiber').name(instance_name)
     log.info('Run console at %s', console_sock)
     console.listen(console_sock)
 
@@ -301,15 +344,15 @@ end
 
 function stop()
     log.info("Stopping instance...")
-    if fio.stat(force_cfg.pid_file) == nil then
-        log.error("Process is not running (pid: %s)", force_cfg.pid_file)
+    local pid_file = default_cfg.pid_file
+    if fio.stat(pid_file) == nil then
+        log.error("Process is not running (pid: %s)", pid_file)
         return 0
     end
 
-    local f = fio.open(force_cfg.pid_file, 'O_RDONLY')
+    local f = fio.open(pid_file, 'O_RDONLY')
     if f == nil then
-        log.error("Can't read pid file %s: %s",
-            force_cfg.pid_file, errno.strerror())
+        log.error("Can't read pid file %s: %s", pid_file, errno.strerror())
         return -1
     end
 
@@ -319,14 +362,14 @@ function stop()
     local pid = tonumber(str)
 
     if pid == nil or pid <= 0 then
-        log.error("Broken pid file %s", force_cfg.pid_file)
-        fio.unlink(force_cfg.pid_file)
+        log.error("Broken pid file %s", pid_file)
+        fio.unlink(pid_file)
         return -1
     end
 
     if ffi.C.kill(pid, 15) < 0 then
         log.error("Can't kill process %d: %s", pid, errno.strerror())
-        fio.unlink(force_cfg.pid_file)
+        fio.unlink(pid_file)
         return -1
     end
     return 0
@@ -335,7 +378,7 @@ end
 function start()
     log.info("Starting instance...")
     box.cfg = wrapper_cfg
-    local success, data = pcall(dofile, instance_lua)
+    local success, data = pcall(dofile, instance_path)
     -- if load fails - show last 10 lines of the log file
     if not success then
         print('Start failed: ' .. data)
@@ -345,6 +388,32 @@ function start()
     end
 end
 
+default_file = find_default_file()
+
+instance_name = find_instance_name(arg[0], arg[2])
+
+local cmd = check_cmd(arg[1])
+
+load_default_file(default_file)
+
+--
+-- Pass the rest of command line arguments to the
+-- instsance
+--
+shift_argv(arg, 0, 2)
+
+instance_path = fio.pathjoin(instance_dir, instance_name .. '.lua')
+
+if not fio.stat(instance_path) then
+    log.error('Instance %s is not found in %s', instance_name, instance_dir)
+    os.exit(-1)
+end
+
+log.info('Found %s.lua in %s', instance_name, instance_dir)
+
+-- create  a path to the control socket (admin console)
+console_sock = fio.pathjoin(fio.dirname(default_cfg.pid_file),
+                            instance_name .. '.control')
 
 if cmd == 'start' then
     start()
@@ -394,18 +463,18 @@ elseif cmd == 'enter' then
     console.start()
     os.exit(0)
 elseif cmd == 'status' then
-    if fio.stat(force_cfg.pid_file) == nil then
+    local pid_file = default_cfg.pid_file
+    if fio.stat(pid_file) == nil then
         if errno() == errno.ENOENT then
-            print(instance .. ' is stopped (pid file does not exist)')
+            print(instance_name .. ' is stopped (pid file does not exist)')
             os.exit(1)
         end
-        log.error("Cant access pidfile %s: %s",
-            force_cfg.pid_file, errno.strerror())
+        log.error("Cant access pidfile %s: %s", pid_file, errno.strerror())
     end
 
     if fio.stat(console_sock) == nil then
         if errno() == errno.ENOENT then
-            log.warn("pidfile is exists, but control socket (%s) isn't",
+            log.warn("pid file exists, but the control socket (%s) doesn't",
                 console_sock)
             os.exit(2)
         end
@@ -423,16 +492,20 @@ elseif cmd == 'status' then
     end
 
     s:close()
-    print(instance .. ' is running (pid:' .. force_cfg.pid_file .. ')')
+    print(instance_name .. ' is running (pid:' .. default_cfg.pid_file .. ')')
     os.exit(0)
 elseif cmd == 'reload' then
-    if fio.stat(arg[2]) == nil then
+    if arg[1] == nil then
+        log.error("Usage: tarantoolctl reload instance_name file.lua")
+        os.exit(1)
+    end
+    if fio.stat(arg[1]) == nil then
         if errno() == errno.ENOENT then
-            print(arg[2] .. ': file not found')
+            print(arg[1] .. ': file not found')
             os.exit(1)
         end
     end
-    dofile(arg[2])
+    dofile(arg[1])
 else
     log.error("Unknown command '%s'", cmd)
     os.exit(-1)
diff --git a/src/lua/fio.cc b/src/lua/fio.cc
index 28507687681f398f3c272a02a6619130d19cc12a..5dfb85b130d2e73e96fc5e843948c542b637a638 100644
--- a/src/lua/fio.cc
+++ b/src/lua/fio.cc
@@ -49,11 +49,18 @@ extern "C" {
 static int
 lbox_fio_open(struct lua_State *L)
 {
-	const char *path = lua_tostring(L, 1);
+	const char *pathname;
+	if (lua_gettop(L) < 1) {
+usage:
+		luaL_error(L, "Usage: fio.open(path, flags, mode)");
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	int flags = lua_tointeger(L, 2);
 	int mode = lua_tointeger(L, 3);
 
-	int fh = coeio_open(path, flags, mode);
+	int fh = coeio_open(pathname, flags, mode);
 	lua_pushinteger(L, fh);
 	return 1;
 }
@@ -63,6 +70,8 @@ lbox_fio_pwrite(struct lua_State *L)
 {
 	int fh = lua_tointeger(L, 1);
 	const char *buf = lua_tostring(L, 2);
+	if (buf == NULL)
+		luaL_error(L, "fio.pwrite(): buffer is not a string");
 	size_t len = lua_tonumber(L, 3);
 	size_t offset = lua_tonumber(L, 4);
 
@@ -108,13 +117,18 @@ lbox_fio_pread(struct lua_State *L)
 static int
 lbox_fio_rename(struct lua_State *L)
 {
-	const char *oldpath, *newpath;
-	int top = lua_gettop(L);
-	if (top < 2 || !(oldpath = lua_tostring(L, 1)) ||
-	    !(newpath = lua_tostring(L, 2))) {
+	const char *oldpath;
+	const char *newpath;
+	if (lua_gettop(L) < 2) {
+usage:
 		luaL_error(L, "Usage: fio.rename(oldpath, newpath)");
-		return 0;
 	}
+	oldpath = lua_tostring(L, 1);
+	newpath = lua_tostring(L, 2);
+
+	if (oldpath == NULL || newpath == NULL)
+		goto usage;
+
 	int res = coeio_rename(oldpath, newpath);
 	lua_pushboolean(L, res == 0);
 	return 1;
@@ -123,14 +137,14 @@ lbox_fio_rename(struct lua_State *L)
 static int
 lbox_fio_unlink(struct lua_State *L)
 {
-	if (lua_gettop(L) < 1)
+	const char *pathname;
+	if (lua_gettop(L) < 1) {
+usage:
 		luaL_error(L, "Usage: fio.unlink(pathname)");
-	const char *pathname = lua_tostring(L, 1);
-	if (!pathname) {
-		errno = EINVAL;
-		lua_pushboolean(L, 0);
-		return 1;
 	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	int res = coeio_unlink(pathname);
 	lua_pushboolean(L, res == 0);
 	return 1;
@@ -149,16 +163,21 @@ lbox_fio_ftruncate(struct lua_State *L)
 static int
 lbox_fio_truncate(struct lua_State *L)
 {
+	const char *pathname;
 	int top = lua_gettop(L);
-	if (top < 1)
+	if (top < 1) {
+usage:
 		luaL_error(L, "Usage: fio.truncate(pathname[, newlen])");
-	const char *path = lua_tostring(L, 1);
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	off_t length;
 	if (top >= 2)
 		length = lua_tonumber(L, 2);
 	else
 		length = 0;
-	int res = coeio_truncate(path, length);
+	int res = coeio_truncate(pathname, length);
 
 	lua_pushboolean(L, res == 0);
 	return 1;
@@ -169,6 +188,9 @@ lbox_fio_write(struct lua_State *L)
 {
 	int fh = lua_tointeger(L, 1);
 	const char *buf = lua_tostring(L, 2);
+	if (buf == NULL)
+		luaL_error(L, "fio.write(): buffer is not a string");
+
 	size_t len = lua_tonumber(L, 3);
 	int res = coeio_write(fh, buf, len);
 	lua_pushinteger(L, res);
@@ -178,14 +200,22 @@ lbox_fio_write(struct lua_State *L)
 static int
 lbox_fio_chown(struct lua_State *L)
 {
-	if (lua_gettop(L) < 3)
+	const char *pathname;
+	if (lua_gettop(L) < 3) {
+usage:
 		luaL_error(L, "Usage: fio.chown(pathname, owner, group)");
-	const char *path = lua_tostring(L, 1);
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
+
 	uid_t owner;
 	if (lua_isnumber(L, 2)) {
 		owner = lua_tointeger(L, 2);
 	} else {
 		const char *username = lua_tostring(L, 2);
+		if (username == NULL)
+			username = "";
 		struct passwd *entry = getpwnam(username);
 		if (!entry) {
 			errno = EINVAL;
@@ -200,6 +230,8 @@ lbox_fio_chown(struct lua_State *L)
 		group = lua_tointeger(L, 3);
 	} else {
 		const char *groupname = lua_tostring(L, 3);
+		if (groupname == NULL)
+			groupname = "";
 		struct group *entry = getgrnam(groupname);
 		if (!entry) {
 			errno = EINVAL;
@@ -208,7 +240,7 @@ lbox_fio_chown(struct lua_State *L)
 		}
 		group = entry->gr_gid;
 	}
-	int res = coeio_chown(path, owner, group);
+	int res = coeio_chown(pathname, owner, group);
 	lua_pushboolean(L, res == 0);
 	return 1;
 }
@@ -216,11 +248,17 @@ lbox_fio_chown(struct lua_State *L)
 static int
 lbox_fio_chmod(struct lua_State *L)
 {
-	if (lua_gettop(L) < 2)
+	const char *pathname;
+	if (lua_gettop(L) < 2) {
+usage:
 		luaL_error(L, "Usage: fio.chmod(pathname, mode)");
-	const char *path = lua_tostring(L, 1);
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
+
 	mode_t mode = lua_tointeger(L, 2);
-	lua_pushboolean(L, coeio_chmod(path, mode) == 0);
+	lua_pushboolean(L, coeio_chmod(pathname, mode) == 0);
 	return 1;
 }
 
@@ -375,9 +413,14 @@ lbox_fio_pushstat(struct lua_State *L, const struct stat *stat)
 static int
 lbox_fio_lstat(struct lua_State *L)
 {
-	if (lua_gettop(L) < 1)
+	const char *pathname;
+	if (lua_gettop(L) < 1) {
+usage:
 		luaL_error(L, "pathname is absent");
-	const char *pathname = lua_tostring(L, 1);
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	struct stat stat;
 
 	int res = coeio_lstat(pathname, &stat);
@@ -391,9 +434,14 @@ lbox_fio_lstat(struct lua_State *L)
 static int
 lbox_fio_stat(struct lua_State *L)
 {
-	if (lua_gettop(L) < 1)
-		luaL_error(L, "pathname is absent");
-	const char *pathname = lua_tostring(L, 1);
+	const char *pathname;
+	if (lua_gettop(L) < 1) {
+usage:
+		luaL_error(L, "Usage: fio.stat(pathname)");
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	struct stat stat;
 
 	int res = coeio_stat(pathname, &stat);
@@ -424,10 +472,13 @@ lbox_fio_mkdir(struct lua_State *L)
 	const char *pathname;
 	int top = lua_gettop(L);
 
-	if (top < 1 || !(pathname = lua_tostring(L, 1))) {
+	if (top < 1) {
+usage:
 		luaL_error(L, "Usage fio.mkdir(pathname[, mode])");
-		return 0;
 	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 
 	mode_t mode;
 
@@ -443,10 +494,13 @@ static int
 lbox_fio_rmdir(struct lua_State *L)
 {
 	const char *pathname;
-	if (lua_gettop(L) < 1 || !(pathname = lua_tostring(L, 1))) {
+	if (lua_gettop(L) < 1) {
+usage:
 		luaL_error(L, "Usage: fio.rmdir(pathname)");
-		return 0;
 	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 
 	lua_pushboolean(L, coeio_rmdir(pathname) == 0);
 	return 1;
@@ -455,10 +509,15 @@ lbox_fio_rmdir(struct lua_State *L)
 static int
 lbox_fio_glob(struct lua_State *L)
 {
-	if (lua_gettop(L) < 1)
+	const char *pattern;
+	if (lua_gettop(L) < 1) {
+usage:
 		luaL_error(L, "Usage: fio.glob(pattern)");
+	}
 
-	const char *pattern = lua_tostring(L, 1);
+	pattern = lua_tostring(L, 1);
+	if (pattern == NULL)
+		goto usage;
 
 	glob_t globbuf;
 	switch (glob(pattern, GLOB_NOESCAPE, NULL, &globbuf)) {
@@ -490,10 +549,16 @@ lbox_fio_glob(struct lua_State *L)
 static int
 lbox_fio_link(struct lua_State *L)
 {
-	if (lua_gettop(L) < 2)
+	const char *target;
+	const char *linkpath;
+	if (lua_gettop(L) < 2) {
+usage:
 		luaL_error(L, "Usage: fio.link(target, linkpath)");
-	const char *target = lua_tostring(L, 1);
-	const char *linkpath = lua_tostring(L, 2);
+	}
+	target = lua_tostring(L, 1);
+	linkpath = lua_tostring(L, 2);
+	if (target == NULL || linkpath == NULL)
+		goto usage;
 	lua_pushboolean(L, coeio_link(target, linkpath) == 0);
 	return 1;
 }
@@ -501,10 +566,16 @@ lbox_fio_link(struct lua_State *L)
 static int
 lbox_fio_symlink(struct lua_State *L)
 {
-	if (lua_gettop(L) < 2)
+	const char *target;
+	const char *linkpath;
+	if (lua_gettop(L) < 2) {
+usage:
 		luaL_error(L, "Usage: fio.symlink(target, linkpath)");
-	const char *target = lua_tostring(L, 1);
-	const char *linkpath = lua_tostring(L, 2);
+	}
+	target = lua_tostring(L, 1);
+	linkpath = lua_tostring(L, 2);
+	if (target == NULL || linkpath == NULL)
+		goto usage;
 	lua_pushboolean(L, coeio_symlink(target, linkpath) == 0);
 	return 1;
 }
@@ -512,11 +583,15 @@ lbox_fio_symlink(struct lua_State *L)
 static int
 lbox_fio_readlink(struct lua_State *L)
 {
-	if (lua_gettop(L) < 1)
+	const char *pathname;
+	if (lua_gettop(L) < 1) {
+usage:
 		luaL_error(L, "Usage: fio.readlink(pathname)");
-
+	}
+	pathname = lua_tostring(L, 1);
+	if (pathname == NULL)
+		goto usage;
 	char *path = (char *)lua_newuserdata(L, PATH_MAX);
-	const char *pathname = lua_tostring(L, 1);
 	int res = coeio_readlink(pathname, path, PATH_MAX);
 	if (res < 0) {
 		lua_pushnil(L);
diff --git a/test/box/fio.result b/test/box/fio.result
index bd6d8634676e95a38c095640dae3c1ff6bd6119a..afe3e6f67cad2e45b0609a5a7edec5c7f72abb95 100644
--- a/test/box/fio.result
+++ b/test/box/fio.result
@@ -14,6 +14,10 @@ fio.umask()
 - 0
 ...
 -- pathjoin
+fio.basename(nil, nil)
+---
+- null
+...
 fio.pathjoin('abc', 'cde')
 ---
 - abc/cde
@@ -31,6 +35,10 @@ fio.pathjoin('/', '/cde')
 - /cde
 ...
 -- basename
+fio.basename(nil)
+---
+- null
+...
 fio.basename('/')
 ---
 - 
@@ -67,6 +75,10 @@ file3 = fio.pathjoin(tmpdir, 'file.3')
 file4 = fio.pathjoin(tmpdir, 'file.4')
 ---
 ...
+fio.open(nil)
+---
+- null
+...
 fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777)
 ---
 ...
@@ -121,13 +133,17 @@ fh1:stat().size
 ---
 - 0
 ...
+fh1:write(nil)
+---
+- true
+...
 fh1:write("Hello, world")
 ---
 - true
 ...
 fh1:stat().size
 ---
-- 133
+- 136
 ...
 fh1:fsync()
 ---
@@ -143,11 +159,11 @@ fio.sync()
 ...
 fh1:pread(512, 121)
 ---
-- Hello, world
+- nilHello, world
 ...
 fh1:pread(5, 121)
 ---
-- Hello
+- nilHe
 ...
 fh1:write("; Ehllo, again")
 ---
@@ -159,15 +175,15 @@ fh1:seek(121)
 ...
 fh1:read(13)
 ---
-- Hello, world;
+- nilHello, wor
 ...
 fh1:read(512)
 ---
-- ' Ehllo, again'
+- ld; Ehllo, again
 ...
 fh1:pread(512, 14 + 121)
 ---
-- Ehllo, again
+- d; Ehllo, again
 ...
 fh1:pwrite("He", 14 + 121)
 ---
@@ -175,12 +191,12 @@ fh1:pwrite("He", 14 + 121)
 ...
 fh1:pread(512, 14 + 121)
 ---
-- Hello, again
+- He Ehllo, again
 ...
 { fh1:stat().size, fio.stat(file1).size }
 ---
-- - 147
-  - 147
+- - 150
+  - 150
 ...
 fh1:seek(121)
 ---
@@ -188,12 +204,20 @@ fh1:seek(121)
 ...
 fh1:read(512)
 ---
-- Hello, world; Hello, again
+- nilHello, worlHe Ehllo, again
+...
+fio.link(nil, nil)
+---
+- error: 'Usage: fio.link(target, linkpath)'
 ...
 fio.link(file1, file2)
 ---
 - true
 ...
+fio.glob(nil)
+---
+- error: 'Usage: fio.glob(pattern)'
+...
 glob = fio.glob(fio.pathjoin(tmpdir, '*'))
 ---
 ...
@@ -229,14 +253,26 @@ fh3:write("abc")
 ---
 - true
 ...
+fio.rename(nil, nil)
+---
+- error: 'Usage: fio.rename(oldpath, newpath)'
+...
 fio.rename(file3, file4)
 ---
 - true
 ...
+fio.symlink(nil, nil)
+---
+- error: 'Usage: fio.symlink(target, linkpath)'
+...
 fio.symlink(file4, file3)
 ---
 - true
 ...
+fio.stat(nil)
+---
+- error: 'Usage: fio.stat(pathname)'
+...
 fio.stat(file3).size
 ---
 - 3
@@ -257,6 +293,10 @@ bit.band(fio.stat(file4).mode, 0x1FF) == 0x1FD
 ---
 - true
 ...
+fio.chmod(nil, 0x1F8)
+---
+- error: 'Usage: fio.chmod(pathname, mode)'
+...
 fio.chmod(file4, 0x1F8) -- 0x770
 ---
 - true
@@ -269,6 +309,10 @@ bit.band(fio.stat(file4).mode, 0x1FF) == 0x1F8
 ---
 - true
 ...
+fio.mkdir(nil)
+---
+- error: Usage fio.mkdir(pathname[, mode])
+...
 fio.mkdir(fio.pathjoin(tmpdir, "dir"))
 ---
 - true
@@ -286,6 +330,10 @@ fio.mkdir(fio.pathjoin(tmpdir, "dir"))
   - false
   - Bad file descriptor
 ...
+fio.rmdir(nil)
+---
+- error: 'Usage: fio.rmdir(pathname)'
+...
 fio.rmdir(fio.pathjoin(tmpdir, "dir"))
 ---
 - true
@@ -319,9 +367,13 @@ fio.unlink()
 ...
 fio.unlink(nil)
 ---
-- false
+- error: 'Usage: fio.unlink(pathname)'
 ...
 -- dirname
+fio.dirname(nil)
+---
+- null
+...
 fio.dirname('abc')
 ---
 - .
diff --git a/test/box/fio.test.lua b/test/box/fio.test.lua
index 8d5b7b5c4e39828c3d2af3aa4a0b775d59086f47..9e72f55ee1d5233938b1fa4f72b35681fbea6de4 100644
--- a/test/box/fio.test.lua
+++ b/test/box/fio.test.lua
@@ -7,12 +7,14 @@ type(fio.umask(0))
 fio.umask()
 
 -- pathjoin
+fio.basename(nil, nil)
 fio.pathjoin('abc', 'cde')
 fio.pathjoin('/', 'abc')
 fio.pathjoin('abc/', '/cde')
 fio.pathjoin('/', '/cde')
 
 -- basename
+fio.basename(nil)
 fio.basename('/')
 fio.basename('abc')
 fio.basename('abc.cde', '.cde')
@@ -30,6 +32,7 @@ file3 = fio.pathjoin(tmpdir, 'file.3')
 file4 = fio.pathjoin(tmpdir, 'file.4')
 
 
+fio.open(nil)
 fh1 = fio.open(file1, { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, 0777)
 fh1 ~= nil
 f1s = fh1:stat()
@@ -46,6 +49,7 @@ f1s:is_blk()
 
 fh1:seek(121)
 fh1:stat().size
+fh1:write(nil)
 fh1:write("Hello, world")
 fh1:stat().size
 fh1:fsync()
@@ -66,8 +70,10 @@ fh1:pread(512, 14 + 121)
 fh1:seek(121)
 fh1:read(512)
 
+fio.link(nil, nil)
 fio.link(file1, file2)
 
+fio.glob(nil)
 glob = fio.glob(fio.pathjoin(tmpdir, '*'))
 #glob
 { string.match(glob[1], '^.*/(.*)'), string.match(glob[2], '^.*/(.*)') }
@@ -80,25 +86,31 @@ bit.band(fh3:stat().mode, 0x1FF) == 0x1FD
 fh3:write("abc")
 
 
+fio.rename(nil, nil)
 fio.rename(file3, file4)
+fio.symlink(nil, nil)
 fio.symlink(file4, file3)
+fio.stat(nil)
 fio.stat(file3).size
 fio.lstat(file3).size ~= fio.stat(file3).size
 fio.lstat(file3).mode ~= fio.stat(file3).mode
 fio.basename(fio.readlink(file3))
 
 bit.band(fio.stat(file4).mode, 0x1FF) == 0x1FD
+fio.chmod(nil, 0x1F8)
 fio.chmod(file4, 0x1F8) -- 0x770
 bit.band(fh3:stat().mode, 0x1FF) == 0x1F8
 bit.band(fio.stat(file4).mode, 0x1FF) == 0x1F8
 
 
+fio.mkdir(nil)
 fio.mkdir(fio.pathjoin(tmpdir, "dir"))
 
 -- cleanup directories
 { fh1:close(), fh3:close() }
 { fh1:close(), errno.strerror(), fh3:close(), errno.strerror() }
 
+fio.rmdir(nil)
 fio.rmdir(fio.pathjoin(tmpdir, "dir"))
 
 { fio.unlink(file1), fio.unlink(file2), fio.unlink(file3), fio.unlink(file4) }
@@ -111,6 +123,7 @@ fio.unlink(nil)
 
 -- dirname
 
+fio.dirname(nil)
 fio.dirname('abc')
 fio.dirname('/abc')
 fio.dirname('/abc/cde')