samba: share select wrappers.
[samba.git] / source3 / client / client.c
index cd41699da31b6923571253667259a96873388a9f..1432d95c229ab0b98c4a65a1d2f80b839e96e6ba 100644 (file)
 */
 
 #include "includes.h"
+#include "popt_common.h"
 #include "client/client_proto.h"
 #include "../librpc/gen_ndr/cli_srvsvc.h"
+#include "../lib/util/select.h"
 
 #ifndef REGISTER
 #define REGISTER 0
@@ -298,14 +300,16 @@ static int do_dskattr(void)
        struct cli_state *targetcli = NULL;
        char *targetpath = NULL;
        TALLOC_CTX *ctx = talloc_tos();
+       NTSTATUS status;
 
        if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
                d_printf("Error in dskattr: %s\n", cli_errstr(cli));
                return 1;
        }
 
-       if (!NT_STATUS_IS_OK(cli_dskattr(targetcli, &bsize, &total, &avail))) {
-               d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
+       status = cli_dskattr(targetcli, &bsize, &total, &avail);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("Error in dskattr: %s\n", nt_errstr(status));
                return 1;
        }
 
@@ -424,6 +428,8 @@ static int do_cd(const char *new_dir)
                        goto out;
                }
        } else {
+               NTSTATUS status;
+
                targetpath = talloc_asprintf(ctx,
                                "%s%s",
                                targetpath,
@@ -438,8 +444,9 @@ static int do_cd(const char *new_dir)
                        goto out;
                }
 
-               if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, targetpath))) {
-                       d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
+               status = cli_chkpath(targetcli, targetpath);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
                        client_set_cur_dir(saved_dir);
                        goto out;
                }
@@ -484,7 +491,7 @@ static int cmd_cd_oneup(void)
  Decide if a file should be operated on.
 ********************************************************************/
 
-static bool do_this_one(file_info *finfo)
+static bool do_this_one(struct file_info *finfo)
 {
        if (!finfo->name) {
                return false;
@@ -517,7 +524,8 @@ static bool do_this_one(file_info *finfo)
  Display info about a file.
 ****************************************************************************/
 
-static void display_finfo(file_info *finfo, const char *dir)
+static void display_finfo(struct cli_state *cli_state, struct file_info *finfo,
+                         const char *dir)
 {
        time_t t;
        TALLOC_CTX *ctx = talloc_tos();
@@ -537,6 +545,7 @@ static void display_finfo(file_info *finfo, const char *dir)
        } else {
                char *afname = NULL;
                uint16_t fnum;
+               NTSTATUS status;
 
                /* skip if this is . or .. */
                if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
@@ -555,19 +564,20 @@ static void display_finfo(file_info *finfo, const char *dir)
                d_printf( "MODE:%s\n", attrib_string(finfo->mode));
                d_printf( "SIZE:%.0f\n", (double)finfo->size);
                d_printf( "MTIME:%s", time_to_asc(t));
-               if (!NT_STATUS_IS_OK(cli_ntcreate(finfo->cli, afname, 0,
-                               CREATE_ACCESS_READ, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
-                               FILE_OPEN, 0x0, 0x0, &fnum))) {
+               status = cli_ntcreate(cli_state, afname, 0,
+                                     CREATE_ACCESS_READ, 0,
+                                     FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                     FILE_OPEN, 0x0, 0x0, &fnum);
+               if (!NT_STATUS_IS_OK(status)) {
                        DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
-                               afname,
-                               cli_errstr( finfo->cli)));
+                                  afname, nt_errstr(status)));
                } else {
                        struct security_descriptor *sd = NULL;
-                       sd = cli_query_secdesc(finfo->cli, fnum, ctx);
+                       sd = cli_query_secdesc(cli_state, fnum, ctx);
                        if (!sd) {
                                DEBUG( 0, ("display_finfo() failed to "
                                        "get security descriptor: %s",
-                                       cli_errstr( finfo->cli)));
+                                       cli_errstr(cli_state)));
                        } else {
                                display_sec_desc(sd);
                        }
@@ -581,7 +591,8 @@ static void display_finfo(file_info *finfo, const char *dir)
  Accumulate size of a file.
 ****************************************************************************/
 
-static void do_du(file_info *finfo, const char *dir)
+static void do_du(struct cli_state *cli_state, struct file_info *finfo,
+                 const char *dir)
 {
        if (do_this_one(finfo)) {
                dir_total += finfo->size;
@@ -594,7 +605,8 @@ static char *do_list_queue = 0;
 static long do_list_queue_size = 0;
 static long do_list_queue_start = 0;
 static long do_list_queue_end = 0;
-static void (*do_list_fn)(file_info *, const char *dir);
+static void (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
+                         const char *dir);
 
 /****************************************************************************
  Functions for do_list_queue.
@@ -711,8 +723,10 @@ static int do_list_queue_empty(void)
  A helper for do_list.
 ****************************************************************************/
 
-static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
+static void do_list_helper(const char *mntpoint, struct file_info *f,
+                          const char *mask, void *state)
 {
+       struct cli_state *cli_state = (struct cli_state *)state;
        TALLOC_CTX *ctx = talloc_tos();
        char *dir = NULL;
        char *dir_end = NULL;
@@ -728,7 +742,7 @@ static void do_list_helper(const char *mntpoint, file_info *f, const char *mask,
 
        if (f->mode & aDIR) {
                if (do_list_dirs && do_this_one(f)) {
-                       do_list_fn(f, dir);
+                       do_list_fn(cli_state, f, dir);
                }
                if (do_list_recurse &&
                    f->name &&
@@ -773,7 +787,7 @@ static void do_list_helper(const char *mntpoint, file_info *f, const char *mask,
        }
 
        if (do_this_one(f)) {
-               do_list_fn(f,dir);
+               do_list_fn(cli_state, f, dir);
        }
        TALLOC_FREE(dir);
 }
@@ -784,7 +798,8 @@ static void do_list_helper(const char *mntpoint, file_info *f, const char *mask,
 
 void do_list(const char *mask,
                        uint16 attribute,
-                       void (*fn)(file_info *, const char *dir),
+                       void (*fn)(struct cli_state *cli_state, struct file_info *,
+                                  const char *dir),
                        bool rec,
                        bool dirs)
 {
@@ -830,7 +845,8 @@ void do_list(const char *mask,
                                continue;
                        }
 
-                       cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
+                       cli_list(targetcli, targetpath, attribute,
+                                do_list_helper, targetcli);
                        remove_do_list_queue_head();
                        if ((! do_list_queue_empty()) && (fn == display_finfo)) {
                                char *next_file = do_list_queue_head();
@@ -858,9 +874,13 @@ void do_list(const char *mask,
        } else {
                /* check for dfs */
                if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
-                       if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
+                       NTSTATUS status;
+
+                       status = cli_list(targetcli, targetpath, attribute,
+                                         do_list_helper, targetcli);
+                       if (!NT_STATUS_IS_OK(status)) {
                                d_printf("%s listing %s\n",
-                                       cli_errstr(targetcli), targetpath);
+                                        nt_errstr(status), targetpath);
                        }
                        TALLOC_FREE(targetpath);
                } else {
@@ -1004,7 +1024,7 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
        int handle = 0;
        uint16_t fnum;
        bool newhandle = false;
-       struct timeval tp_start;
+       struct timespec tp_start;
        uint16 attr;
        SMB_OFF_T size;
        off_t start = 0;
@@ -1029,10 +1049,12 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
                return 1;
        }
 
-       GetTimeOfDay(&tp_start);
+       clock_gettime_mono(&tp_start);
 
-       if (!NT_STATUS_IS_OK(cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum))) {
-               d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
+       status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("%s opening remote file %s\n", nt_errstr(status),
+                        rname);
                return 1;
        }
 
@@ -1079,8 +1101,9 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
                return 1;
        }
 
-       if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
-               d_printf("Error %s closing remote file\n",cli_errstr(cli));
+       status = cli_close(targetcli, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("Error %s closing remote file\n", nt_errstr(status));
                rc = 1;
        }
 
@@ -1093,13 +1116,11 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
        }
 
        {
-               struct timeval tp_end;
+               struct timespec tp_end;
                int this_time;
 
-               GetTimeOfDay(&tp_end);
-               this_time =
-                       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
-                       (tp_end.tv_usec - tp_start.tv_usec)/1000;
+               clock_gettime_mono(&tp_end);
+               this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
                get_total_time_ms += this_time;
                get_total_size += nread;
 
@@ -1153,7 +1174,8 @@ static int cmd_get(void)
  Do an mget operation on one file.
 ****************************************************************************/
 
-static void do_mget(file_info *finfo, const char *dir)
+static void do_mget(struct cli_state *cli_state, struct file_info *finfo,
+                   const char *dir)
 {
        TALLOC_CTX *ctx = talloc_tos();
        char *rname = NULL;
@@ -1384,15 +1406,17 @@ static bool do_mkdir(const char *name)
        TALLOC_CTX *ctx = talloc_tos();
        struct cli_state *targetcli;
        char *targetname = NULL;
+       NTSTATUS status;
 
        if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
                d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
                return false;
        }
 
-       if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetname))) {
+       status = cli_mkdir(targetcli, targetname);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s making remote directory %s\n",
-                        cli_errstr(targetcli),name);
+                        nt_errstr(status),name);
                return false;
        }
 
@@ -1406,10 +1430,12 @@ static bool do_mkdir(const char *name)
 static bool do_altname(const char *name)
 {
        fstring altname;
+       NTSTATUS status;
 
-       if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+       status = cli_qpathinfo_alt_name(cli, name, altname);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s getting alt name for %s\n",
-                        cli_errstr(cli),name);
+                        nt_errstr(status),name);
                return false;
        }
        d_printf("%s\n", altname);
@@ -1654,7 +1680,7 @@ static int do_put(const char *rname, const char *lname, bool reput)
        XFILE *f;
        SMB_OFF_T start = 0;
        int rc = 0;
-       struct timeval tp_start;
+       struct timespec tp_start;
        struct cli_state *targetcli;
        char *targetname = NULL;
        struct push_state state;
@@ -1665,7 +1691,7 @@ static int do_put(const char *rname, const char *lname, bool reput)
                return 1;
        }
 
-       GetTimeOfDay(&tp_start);
+       clock_gettime_mono(&tp_start);
 
        if (reput) {
                status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
@@ -1724,8 +1750,10 @@ static int do_put(const char *rname, const char *lname, bool reput)
                rc = 1;
        }
 
-       if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
-               d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
+       status = cli_close(targetcli, fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("%s closing remote file %s\n", nt_errstr(status),
+                        rname);
                if (f != x_stdin) {
                        x_fclose(f);
                }
@@ -1737,13 +1765,11 @@ static int do_put(const char *rname, const char *lname, bool reput)
        }
 
        {
-               struct timeval tp_end;
+               struct timespec tp_end;
                int this_time;
 
-               GetTimeOfDay(&tp_end);
-               this_time =
-                       (tp_end.tv_sec - tp_start.tv_sec)*1000 +
-                       (tp_end.tv_usec - tp_start.tv_usec)/1000;
+               clock_gettime_mono(&tp_end);
+               this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
                put_total_time_ms += this_time;
                put_total_size += state.nread;
 
@@ -2132,10 +2158,12 @@ static int cmd_queue(void)
  Delete some files.
 ****************************************************************************/
 
-static void do_del(file_info *finfo, const char *dir)
+static void do_del(struct cli_state *cli_state, struct file_info *finfo,
+                  const char *dir)
 {
        TALLOC_CTX *ctx = talloc_tos();
        char *mask = NULL;
+       NTSTATUS status;
 
        mask = talloc_asprintf(ctx,
                                "%s%c%s",
@@ -2151,9 +2179,10 @@ static void do_del(file_info *finfo, const char *dir)
                return;
        }
 
-       if (!NT_STATUS_IS_OK(cli_unlink(finfo->cli, mask, aSYSTEM | aHIDDEN))) {
+       status = cli_unlink(cli_state, mask, aSYSTEM | aHIDDEN);
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s deleting remote file %s\n",
-                               cli_errstr(finfo->cli),mask);
+                        nt_errstr(status), mask);
        }
        TALLOC_FREE(mask);
 }
@@ -2202,6 +2231,7 @@ static int cmd_wdel(void)
        uint16 attribute;
        struct cli_state *targetcli;
        char *targetname = NULL;
+       NTSTATUS status;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("wdel 0x<attrib> <wcard>\n");
@@ -2227,8 +2257,10 @@ static int cmd_wdel(void)
                return 1;
        }
 
-       if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetname, attribute))) {
-               d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
+       status = cli_unlink(targetcli, targetname, attribute);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("%s deleting remote files %s\n", nt_errstr(status),
+                        targetname);
        }
        return 0;
 }
@@ -2834,21 +2866,16 @@ static int cmd_symlink(void)
        char *newname = NULL;
        char *buf = NULL;
        char *buf2 = NULL;
-       char *targetname = NULL;
-       struct cli_state *targetcli;
+       struct cli_state *newcli;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
            !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
                d_printf("symlink <oldname> <newname>\n");
                return 1;
        }
-       oldname = talloc_asprintf(ctx,
-                       "%s%s",
-                       client_get_cur_dir(),
-                       buf);
-       if (!oldname) {
-               return 1;
-       }
+       /* Oldname (link target) must be an untouched blob. */
+       oldname = buf;
+
        newname = talloc_asprintf(ctx,
                        "%s%s",
                        client_get_cur_dir(),
@@ -2857,19 +2884,20 @@ static int cmd_symlink(void)
                return 1;
        }
 
-       if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
+       /* New name must be present in share namespace. */
+       if (!cli_resolve_path(ctx, "", auth_info, cli, newname, &newcli, &newname)) {
                d_printf("link %s: %s\n", oldname, cli_errstr(cli));
                return 1;
        }
 
-       if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+       if (!SERVER_HAS_UNIX_CIFS(newcli)) {
                d_printf("Server doesn't support UNIX CIFS calls.\n");
                return 1;
        }
 
-       if (!NT_STATUS_IS_OK(cli_posix_symlink(targetcli, targetname, newname))) {
+       if (!NT_STATUS_IS_OK(cli_posix_symlink(newcli, oldname, newname))) {
                d_printf("%s symlinking files (%s -> %s)\n",
-                       cli_errstr(targetcli), newname, targetname);
+                       cli_errstr(newcli), newname, newname);
                return 1;
        }
 
@@ -4202,7 +4230,7 @@ struct completion_remote {
 };
 
 static void completion_remote_filter(const char *mnt,
-                               file_info *f,
+                               struct file_info *f,
                                const char *mask,
                                void *state)
 {
@@ -4271,6 +4299,7 @@ static char **remote_completion(const char *text, int len)
        struct cli_state *targetcli = NULL;
        int i;
        struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
+       NTSTATUS status;
 
        /* can't have non-static initialisation on Sun CC, so do it
           at run time here */
@@ -4329,8 +4358,9 @@ static char **remote_completion(const char *text, int len)
        if (!cli_resolve_path(ctx, "", auth_info, cli, dirmask, &targetcli, &targetpath)) {
                goto cleanup;
        }
-       if (cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN,
-                               completion_remote_filter, (void *)&info) < 0) {
+       status = cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN,
+                         completion_remote_filter, (void *)&info);
+       if (!NT_STATUS_IS_OK(status)) {
                goto cleanup;
        }
 
@@ -4475,9 +4505,11 @@ static void readline_callback(void)
        fd_set fds;
        struct timeval timeout;
        static time_t last_t;
+       struct timespec now;
        time_t t;
 
-       t = time(NULL);
+       clock_gettime_mono(&now);
+       t = now.tv_sec;
 
        if (t - last_t < 5)
                return;
@@ -4654,7 +4686,7 @@ static int process(const char *base_directory)
 static int do_host_query(const char *query_host)
 {
        cli = cli_cm_open(talloc_tos(), NULL,
-                       query_host, "IPC$", auth_info, true, smb_encrypt,
+                       have_ip ? dest_ss_str : query_host, "IPC$", auth_info, true, smb_encrypt,
                        max_protocol, port, name_type);
        if (!cli)
                return 1;
@@ -4680,7 +4712,8 @@ static int do_host_query(const char *query_host)
 
                cli_shutdown(cli);
                cli = cli_cm_open(talloc_tos(), NULL,
-                               query_host, "IPC$", auth_info, true, smb_encrypt,
+                               have_ip ? dest_ss_str : query_host, "IPC$",
+                               auth_info, true, smb_encrypt,
                                max_protocol, 139, name_type);
        }