2 * Copyright (c) 1995 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <arla_local.h>
41 char *default_log_file
= "/dev/stderr";
42 char *default_arla_cachedir
= ".arlacache";
43 int client_port
= 4712;
46 /* creds used for all the interactive usage */
48 static CredCacheEntry
*ce
;
51 static VenusFid rootcwd
;
53 static int arla_chdir(int, char **);
54 static int arla_ls(int, char **);
55 static int arla_cat(int, char **);
56 static int arla_cp(int, char **);
57 static int arla_sleep(int, char **);
58 static int arla_wc(int, char **);
59 static int help(int, char **);
60 static int arla_quit(int, char **);
61 static int arla_checkserver(int, char **);
62 static int arla_conn_status(int, char **);
63 static int arla_connect(int, char **);
64 static int arla_vol_status(int, char **);
65 static int arla_cred_status(int, char **);
66 static int arla_fcache_status(int, char **);
67 static int arla_cell_status (int, char **);
68 static int arla_sysname(int, char**);
69 static int arla_mkdir (int, char**);
70 static int arla_rmdir (int, char**);
71 static int arla_rm (int, char**);
72 static int arla_put (int, char**);
73 static int arla_get (int, char**);
75 static int arla_rx_status(int argc
, char **argv
);
77 static int arla_flushfid(int argc
, char **argv
);
79 static char *copy_dirname(const char *s
);
80 static char *copy_basename(const char *s
);
83 static SL_cmd cmds
[] = {
84 {"chdir", arla_chdir
, "chdir directory"},
86 {"ls", arla_ls
, "ls"},
87 {"cat", arla_cat
, "cat file"},
88 {"cp", arla_cp
, "copy file"},
89 {"sleep", arla_sleep
, "sleep seconds"},
90 {"wc", arla_wc
, "wc file"},
91 {"mkdir", arla_mkdir
, "mkdir dir"},
92 {"rmdir", arla_rmdir
, "rmdir dir"},
93 {"rm", arla_rm
, "rm file"},
94 {"put", arla_put
, "put localfile [afsfile]"},
95 {"get", arla_get
, "get afsfile [localfile]"},
96 {"help", help
, "help"},
98 {"checkservers", arla_checkserver
, "poll servers are down"},
99 {"conn-status", arla_conn_status
, "connection status"},
100 {"vol-status", arla_vol_status
, "volume cache status"},
101 {"cred-status", arla_cred_status
, "credentials status"},
102 {"fcache-status", arla_fcache_status
, "file cache status"},
103 {"cell-status", arla_cell_status
, "cell status"},
105 {"rx-status", arla_rx_status
, "rx connection status"},
107 {"flushfid", arla_flushfid
, "flush a fid from the cache"},
108 {"quit", arla_quit
, "quit"},
110 {"sysname", arla_sysname
, "sysname"},
111 {"connect", arla_connect
,
112 "connect [connected|fetch-only|disconnected|callback-connected]"},
117 * Return a malloced copy of the dirname of `s'
121 copy_dirname (const char *s
)
126 p
= strrchr (s
, '/');
129 res
= malloc (p
- s
+ 1);
132 memmove (res
, s
, p
- s
);
138 * Return the basename of `s'.
139 * The result is malloc'ed.
143 copy_basename (const char *s
)
148 p
= strrchr (s
, '/');
154 res
= malloc (q
- p
+ 1);
157 memmove (res
, p
, q
- p
);
167 arla_quit (int argc
, char **argv
)
169 printf("Thank you for using arla\n");
174 arla_flushfid(int argc
, char **argv
)
176 AFSCallBack broken_callback
= {0, 0, CBDROPPED
};
180 fprintf(stderr
, "flushfid fid\n");
184 if ((sscanf(argv
[1], "%d.%d.%d.%d", &fid
.Cell
, &fid
.fid
.Volume
,
185 &fid
.fid
.Vnode
, &fid
.fid
.Unique
)) == 4) {
187 } else if ((sscanf(argv
[1], "%d.%d.%d", &fid
.fid
.Volume
,
188 &fid
.fid
.Vnode
, &fid
.fid
.Unique
)) == 3) {
191 fprintf(stderr
, "flushfid fid\n");
195 fcache_stale_entry(fid
, broken_callback
);
202 arla_chdir (int argc
, char **argv
)
205 printf ("usage: %s dir\n", argv
[0]);
209 if(cm_walk (cwd
, argv
[1], &cwd
))
210 printf ("walk %s failed\n", argv
[1]);
215 print_dir (VenusFid
*fid
, const char *name
, void *v
)
217 printf("(%d, %d, %d, %d): %s\n", fid
->Cell
,
220 fid
->fid
.Unique
, name
);
230 print_dir_long (VenusFid
*fid
, const char *name
, void *v
)
234 struct ls_context
*context
= (struct ls_context
*)v
;
236 CredCacheEntry
*ce
= context
->ce
;
238 VenusFid
*dir_fid
= context
->dir_fid
;
243 if (VenusFid_cmp(fid
, dir_fid
) == 0)
246 ret
= followmountpoint (fid
, dir_fid
, NULL
, &ce
);
248 printf ("follow %s: %d\n", name
, ret
);
252 /* Have we follow a mountpoint to ourself ? */
253 if (VenusFid_cmp(fid
, dir_fid
) == 0)
256 ret
= fcache_get(&entry
, *fid
, context
->ce
);
258 printf("%s: %d\n", name
, ret
);
262 ret
= cm_getattr (entry
, context
->ce
, &ae
);
264 fcache_release(entry
);
265 printf ("%s: %d\n", name
, ret
);
269 switch (entry
->status
.FileType
) {
283 printf("(%4d, %8d, %8d, %8d): ",
289 ti
= entry
->status
.ClientModTime
;
291 strftime (timestr
, sizeof(timestr
), "%Y-%m-%d", t
);
292 printf ("%c%c%c%c%c%c%c%c%c%c %2d %6d %6d %8lu %s ",
294 entry
->status
.UnixModeBits
& 0x100 ? 'r' : '-',
295 entry
->status
.UnixModeBits
& 0x080 ? 'w' : '-',
296 entry
->status
.UnixModeBits
& 0x040 ? 'x' : '-',
297 entry
->status
.UnixModeBits
& 0x020 ? 'r' : '-',
298 entry
->status
.UnixModeBits
& 0x010 ? 'w' : '-',
299 entry
->status
.UnixModeBits
& 0x008 ? 'x' : '-',
300 entry
->status
.UnixModeBits
& 0x004 ? 'r' : '-',
301 entry
->status
.UnixModeBits
& 0x002 ? 'w' : '-',
302 entry
->status
.UnixModeBits
& 0x001 ? 'x' : '-',
303 entry
->status
.LinkCount
,
306 (unsigned long)fcache_get_status_length(&entry
->status
),
309 printf ("v %d ", entry
->status
.DataVersion
);
311 printf ("%s\n", name
);
312 fcache_release(entry
);
317 arla_ls (int argc
, char **argv
)
319 struct getargs args
[] = {
320 {NULL
, 'l', arg_flag
, NULL
},
325 struct ls_context context
;
328 args
[0].value
= &l_flag
;
330 if (getarg (args
, sizeof(args
)/sizeof(*args
), argc
, argv
, &optind
)) {
331 arg_printusage (args
, sizeof(args
)/sizeof(*args
), "ls", NULL
);
334 context
.dir_fid
= &cwd
;
336 error
= fcache_get(&entry
, cwd
, ce
);
338 printf ("fcache_get failed: %s\n", koerr_gettext(error
));
342 error
= adir_readdir (&entry
, l_flag
? print_dir_long
: print_dir
,
344 fcache_release(entry
);
346 printf ("adir_readdir failed: %s\n", koerr_gettext(error
));
354 arla_sysname (int argc
, char **argv
)
358 printf("sysname: %s\n", fcache_getdefsysname());
361 fcache_setdefsysname(argv
[1]);
362 printf("setting sysname to: %s\n", fcache_getdefsysname());
365 printf("syntax: sysname <sysname>\n");
372 arla_mkdir (int argc
, char **argv
)
380 AFSStoreStatus store_attr
;
382 AFSFetchStatus fetch_attr
;
385 printf ("usage: %s file\n", argv
[0]);
389 argcopy
= strdup(argv
[1]);
392 basename
= strrchr(argcopy
, '/');
393 if (basename
== NULL
) {
402 if (cm_walk (cwd
, dirname
, &fid
) == 0) {
404 ret
= fcache_get(&e
, fid
, ce
);
406 printf ("fcache_get failed: %d\n", ret
);
412 store_attr
.ClientModTime
= 0;
413 store_attr
.Owner
= 0;
414 store_attr
.Group
= 0;
415 store_attr
.UnixModeBits
= 0;
416 store_attr
.SegSize
= 0;
417 ret
= cm_mkdir(&e
, basename
, &store_attr
, &res
, &fetch_attr
, &ce
);
419 arla_warn (ADEBWARN
, ret
,
420 "%s: cannot create directory `%s'",
430 arla_rmdir (int argc
, char **argv
)
440 printf ("usage: %s file\n", argv
[0]);
444 argcopy
= strdup(argv
[1]);
447 basename
= strrchr(argcopy
, '/');
448 if (basename
== NULL
) {
457 if (cm_walk (cwd
, dirname
, &fid
) == 0) {
459 ret
= fcache_get(&e
, fid
, ce
);
461 printf ("fcache_get failed: %d\n", ret
);
466 ret
= cm_rmdir(&e
, basename
, &ce
);
468 arla_warn (ADEBWARN
, ret
,
469 "%s: cannot remove directory `%s'",
478 arla_rm (int argc
, char **argv
)
487 printf ("usage: %s file\n", argv
[0]);
490 dirname
= copy_dirname(argv
[1]);
492 err(1, "copy_dirname");
493 basename
= copy_basename(argv
[1]);
494 if (basename
== NULL
)
495 err(1, "copy_basename");
497 if(cm_walk (cwd
, dirname
, &fid
) == 0) {
499 ret
= fcache_get(&e
, fid
, ce
);
501 printf ("fcache_get failed: %d\n", ret
);
507 ret
= cm_remove(&e
, basename
, &ce
);
509 arla_warn (ADEBWARN
, ret
,
510 "%s: cannot remove file `%s'",
521 arla_put (int argc
, char **argv
)
532 AFSStoreStatus store_attr
;
533 AFSFetchStatus fetch_attr
;
540 if (argc
!= 2 && argc
!= 3) {
541 printf ("usage: %s localfile [afsfile]\n", argv
[0]);
547 localbasename
= copy_basename(localname
);
548 if (localbasename
== NULL
)
549 err(1, "copy_basename");
554 afsname
= localbasename
;
557 afsdirname
= copy_dirname(afsname
);
558 if (afsdirname
== NULL
)
559 err(1, "copy_dirname");
560 afsbasename
= copy_basename(afsname
);
561 if (afsbasename
== NULL
)
562 err(1, "copy_basename");
565 printf("localbasename: *%s* afsname: *%s* afsdirname: *%s* afsbasename: *%s*\n",
566 localbasename
, afsname
, afsdirname
, afsbasename
);
568 local_fd
= open (localname
, O_RDONLY
, 0);
571 printf ("open %s: %s\n", localname
, strerror(errno
));
576 if(cm_walk (cwd
, afsdirname
, &dirfid
))
579 ce
= cred_get (dirfid
.Cell
, getuid(), CRED_ANY
);
581 ret
= fcache_get(&e
, dirfid
, ce
);
583 printf ("fcache_get failed: %d\n", ret
);
588 memset(&store_attr
, 0, sizeof(store_attr
));
590 ret
= cm_create(&e
, afsbasename
, &store_attr
, &fid
, &fetch_attr
, &ce
);
593 arla_warn (ADEBWARN
, ret
,
594 "%s: cannot create file `%s'",
600 ret
= cm_lookup (&e
, afsbasename
, &fid
, &ce
, 1);
602 arla_warn (ADEBWARN
, ret
,
603 "%s: cannot open file `%s'",
614 ret
= fcache_get(&e
, fid
, ce
);
616 printf ("fcache_get failed: %d\n", ret
);
621 ret
= fcache_get_data (&e
, &ce
, 0);
624 printf ("fcache_get_data failed: %d\n", ret
);
629 afs_fd
= fcache_open_file (e
, O_WRONLY
);
633 printf ("fcache_open_file failed: %d\n", errno
);
638 ret
= ftruncate(afs_fd
, 0);
641 printf ("ftruncate failed: %d\n", errno
);
644 while ((ret
= read (local_fd
, buf
, sizeof(buf
))) > 0) {
645 write_ret
= write (afs_fd
, buf
, ret
);
647 printf("write failed: %d\n", errno
);
650 } else if (write_ret
!= ret
) {
651 printf("short write: %d should be %d\n", write_ret
, ret
);
660 memset(&store_attr
, 0, sizeof(store_attr
));
662 ret
= cm_close (e
, NNPFS_WRITE
, &store_attr
, ce
);
664 arla_warn (ADEBWARN
, ret
,
665 "%s: cannot close file `%s'",
682 arla_get (int argc
, char **argv
)
688 arla_cat_et_wc (int argc
, char **argv
, int do_cat
, int out_fd
)
698 printf ("usage: %s file\n", argv
[0]);
701 if(cm_walk (cwd
, argv
[1], &fid
) == 0) {
703 ret
= fcache_get(&e
, fid
, ce
);
705 printf ("fcache_get failed: %d\n", ret
);
709 ret
= fcache_get_data (&e
, &ce
, 0);
712 printf ("fcache_get_data failed: %d\n", ret
);
716 fd
= fcache_open_file (e
, O_RDONLY
);
720 printf ("fcache_open_file failed: %d\n", errno
);
723 while ((ret
= read (fd
, buf
, sizeof(buf
))) > 0) {
725 write (out_fd
, buf
, ret
);
730 printf("%lu %s\n", (unsigned long)size
, argv
[1]);
738 arla_cat (int argc
, char **argv
)
740 return arla_cat_et_wc(argc
, argv
, 1, STDOUT_FILENO
);
744 arla_cp (int argc
, char **argv
)
750 printf ("usage: %s from-file to-file\n", argv
[0]);
754 fd
= open (argv
[2], O_CREAT
|O_WRONLY
|O_TRUNC
, 0600);
764 ret
= arla_cat_et_wc(argc
-1, nargv
, 1, fd
);
771 arla_sleep(int argc
, char **argv
)
776 printf ("usage: %s <time>\n", argv
[0]);
780 tv
.tv_sec
= atoi(argv
[1]);
782 IOMGR_Select(0, NULL
, NULL
, NULL
, &tv
);
788 arla_wc (int argc
, char **argv
)
790 return arla_cat_et_wc(argc
, argv
, 0, -1);
795 help (int argc
, char **argv
)
797 sl_help(cmds
, argc
, argv
);
802 arla_checkserver (int argc
, char **argv
)
805 int num
= sizeof(hosts
)/sizeof(hosts
[0]);
807 conn_downhosts(cwd
.Cell
, hosts
, &num
, 0);
808 if (num
< 0 || num
> sizeof(hosts
)/sizeof(hosts
[0])) {
809 fprintf (stderr
, "conn_downhosts returned bogus num: %d\n", num
);
813 printf ("no servers down in %s\n", cell_num2name(cwd
.Cell
));
817 in
.s_addr
= hosts
[num
];
818 printf ("down: %s\n", inet_ntoa(in
));
827 arla_conn_status (int argc
, char **argv
)
834 arla_vol_status (int argc
, char **argv
)
841 arla_cred_status (int argc
, char **argv
)
848 arla_fcache_status (int argc
, char **argv
)
855 arla_cell_status (int argc
, char **argv
)
860 printf ("usage: %s <cell-name>\n", argv
[0]);
863 c
= cell_get_by_name(argv
[1]);
865 printf ("no such cell\n");
867 cell_print_cell (c
, stdout
);
872 arla_connect (int argc
, char **argv
)
874 int error
= (argc
> 2) ? 1 : 0;
877 struct nnpfs_cred cred
;
879 if (strncmp("dis", argv
[1], 3) == 0)
880 mode
= arla_CONNMODE_DISCONN
;
881 else if (strncmp("fetch", argv
[1], 5) == 0)
882 mode
= arla_CONNMODE_FETCH
;
883 else if (strncmp("conn", argv
[1], 4) == 0)
884 mode
= arla_CONNMODE_CONN
;
885 else if (strncmp(argv
[1], "call", 4) == 0)
886 mode
= arla_CONNMODE_CONN_WITHCALLBACKS
;
891 error
= set_connmode(mode
, &cred
);
894 printf("usage: %s [connected|fetch|disconnected|callback-connected]\n",
901 case arla_CONNMODE_CONN
:
902 printf("Connected mode\n");
904 case arla_CONNMODE_FETCH
:
905 printf("Fetch only mode\n");
907 case arla_CONNMODE_DISCONN
:
908 printf("Disconnected mode\n");
911 printf("Unknown or error\n");
919 arla_rx_status(int argc
, char **argv
)
921 rx_PrintStats(stderr
);
930 get_cred(const char *princ
, const char *inst
, const char *krealm
,
936 k_errno
= krb_get_cred((char*)princ
, (char*)inst
, (char*)krealm
, c
);
938 if(k_errno
!= KSUCCESS
) {
939 k_errno
= krb_mk_req(&foo
, (char*)princ
, (char*)inst
, (char*)krealm
, 0);
940 if (k_errno
== KSUCCESS
)
941 k_errno
= krb_get_cred((char*)princ
, (char*)inst
, (char*)krealm
, c
);
950 arla_start (char *device_file
, const char *cache_dir
, int argc
, char **argv
)
956 struct cred_rxkad cred
;
960 const char *this_cell
= cell_getthiscell ();
961 const char *db_server
= cell_findnamedbbyname (this_cell
);
963 if (db_server
== NULL
)
964 arla_errx (1, ADEBERROR
,
965 "no db server for cell %s", this_cell
);
966 realm
= krb_realmofhost (db_server
);
968 ret
= get_cred("afs", this_cell
, realm
, &c
);
970 ret
= get_cred("afs", "", realm
, &c
);
973 arla_warnx (ADEBWARN
,
974 "getting ticket for %s: %s",
976 krb_get_err_text (ret
));
980 memset(&cred
, 0, sizeof(cred
));
982 memcpy(&cred
.ct
.HandShakeKey
, c
.session
, sizeof(cred
.ct
.AuthHandle
));
983 cred
.ct
.AuthHandle
= c
.kvno
;
984 cred
.ct
.ViceId
= getuid();
985 cred
.ct
.BeginTimestamp
= c
.issue_date
+ 1;
986 cred
.ct
.EndTimestamp
= krb_life_to_time(c
.issue_date
, c
.lifetime
);
988 cred
.ticket_len
= c
.ticket_st
.length
;
989 if (cred
.ticket_len
> sizeof(cred
.ticket
))
990 arla_errx (1, ADEBERROR
, "ticket too large");
991 memcpy(cred
.ticket
, c
.ticket_st
.dat
, cred
.ticket_len
);
993 cred_add (getuid(), CRED_KRB4
, 2, cell_name2num(cell_getthiscell()),
994 2, &cred
, sizeof(cred
), getuid());
999 ce
= cred_get (cell_name2num(cell_getthiscell()), getuid(), CRED_ANY
);
1001 assert (ce
!= NULL
);
1003 nnpfs_message_init ();
1004 kernel_opendevice ("null");
1006 arla_warnx (ADEBINIT
, "Getting root...");
1007 error
= getroot (&rootcwd
, ce
);
1009 arla_err (1, ADEBERROR
, error
, "getroot");
1011 arla_warnx(ADEBINIT
, "arla loop started");
1014 error
= sl_command(cmds
, argc
, argv
);
1016 errx (1, "%s: Unknown command\n", argv
[0]);
1018 sl_loop(cmds
, "arla> ");
1021 fcache_giveup_all_callbacks();
1027 get_default_cache_dir (void)
1029 static char cache_path
[MAXPATHLEN
];
1032 home
= getenv("HOME");
1036 snprintf (cache_path
, sizeof(cache_path
), "%s/.arla-cache",
1041 static struct getargs args
[] = {
1042 {"conffile", 'c', arg_string
, &conf_file
,
1043 "path to configuration file", "file"},
1044 {"check-consistency", 'C', arg_flag
, &cm_consistency
,
1045 "if we want extra paranoid consistency checks", NULL
},
1046 {"log", 'l', arg_string
, &log_file
,
1047 "where to write log (stderr (default), syslog, or path to file)", NULL
},
1048 {"debug", 0, arg_string
, &debug_levels
,
1049 "what to write in the log", NULL
},
1050 {"connected-mode", 0, arg_string
, &connected_mode_string
,
1051 "initial connected mode [conncted|fetch-only|disconnected]", NULL
},
1052 {"dynroot", 'D', arg_flag
, &dynroot_enable
,
1053 "if dynroot is enabled", NULL
},
1055 {"rxkad-level", 'r', arg_string
, &rxkad_level_string
,
1056 "the rxkad level to use (clear, auth or crypt)", NULL
},
1058 {"sysname", 's', arg_string
, &argv_sysname
,
1059 "set the sysname of this system", NULL
},
1060 {"root-volume",0, arg_string
, &root_volume
},
1061 {"port", 0, arg_integer
, &client_port
,
1062 "port number to use", "number"},
1063 {"recover", 'z', arg_negative_flag
, &recover
,
1064 "don't recover state", NULL
},
1065 {"cache-dir", 0, arg_string
, &cache_dir
,
1066 "cache directory", "directory"},
1067 {"workers", 0, arg_integer
, &num_workers
,
1068 "number of worker threads", NULL
},
1069 {"fake-mp", 0, arg_flag
, &fake_mp
,
1070 "enable fake mountpoints", NULL
},
1071 {"version", 0, arg_flag
, &version_flag
,
1073 {"help", 0, arg_flag
, &help_flag
,
1080 arg_printusage (args
, sizeof(args
)/sizeof(*args
), NULL
, "[command]");
1085 main (int argc
, char **argv
)
1090 setprogname (argv
[0]);
1094 if (getarg (args
, sizeof(args
)/sizeof(*args
), argc
, argv
, &optind
))
1104 print_version (NULL
);
1108 default_log_file
= "/dev/stderr";
1115 struct timeval tv
= { 0, 10000} ;
1116 IOMGR_Select(0, NULL
, NULL
, NULL
, &tv
);
1119 arla_start (NULL
, cache_dir
, argc
, argv
);