1 /* Server for the Midnight Commander Virtual File System.
3 Copyright (C) 1995, 1996, 1997 The Free Software Foundation
6 Miguel de Icaza, 1995, 1997,
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 opendir instead of keeping its table of file handles could return
25 the pointer and expect the client to send a proper value back each
28 We should use syslog to register login/logout.
32 /* {{{ Includes and global variables */
45 # include <sys/param.h>
47 # define NGROUPS_MAX NGROUPS
53 #include <sys/types.h>
59 /* Network include files */
60 #include <sys/socket.h>
61 #include <netinet/in.h>
63 #ifdef HAVE_ARPA_INET_H
64 #include <arpa/inet.h>
68 # include <rpc/pmap_prot.h>
69 # ifdef HAVE_RPC_PMAP_CLNT_H
70 # include <rpc/pmap_clnt.h>
74 /* Authentication include files */
77 # include <security/pam_misc.h>
78 # ifndef PAM_ESTABLISH_CRED
79 # define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
85 extern char *crypt (const char *, const char *);
86 #endif /* !HAVE_CRYPT_H */
87 #endif /* !HAVE_PAM */
96 /* replacement for g_free() from glib */
98 #define g_free(x) do {if (x) free (x);} while (0)
100 /* We don't care about SIGPIPE */
103 /* The socket from which we accept commands */
106 /* Requested version number from client */
107 static int clnt_version
;
109 /* If non zero, we accept further commands */
113 char *home_dir
= NULL
;
117 /* Were we started from inetd? */
118 int inetd_started
= 0;
120 /* Are we running as a daemon? */
129 /* port number in which we listen to connections,
130 * if zero, we try to contact the portmapper to get a port, and
131 * if it's not possible, then we use a hardcoded value
135 /* if the server will use rcmd based authentication (hosts.equiv .rhosts) */
138 #define OPENDIR_HANDLES 8
140 #define DO_QUIT_VOID() \
147 /* Only used by get_port_number */
148 #define DO_QUIT_NONVOID(a) \
157 static int quit_server
;
158 static int return_code
;
162 /* {{{ Misc routines */
165 send_status (int status
, int errno_number
)
167 rpc_send (msock
, RPC_INT
, status
, RPC_INT
, errno_number
, RPC_END
);
173 /* {{{ File with handle operations */
178 int handle
, flags
, mode
;
181 rpc_get (msock
, RPC_STRING
, &arg
, RPC_INT
, &flags
, RPC_INT
, &mode
,
184 handle
= open (arg
, flags
, mode
);
185 send_status (handle
, errno
);
192 int handle
, count
, n
;
195 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
196 data
= malloc (count
);
198 send_status (-1, ENOMEM
);
202 printf ("count=%d\n", count
);
203 n
= read (handle
, data
, count
);
205 printf ("result=%d\n", n
);
207 send_status (-1, errno
);
211 rpc_send (msock
, RPC_BLOCK
, n
, data
, RPC_END
);
219 int handle
, count
, status
, written
= 0;
222 rpc_get (msock
, RPC_INT
, &handle
, RPC_INT
, &count
, RPC_END
);
225 int nbytes
= count
> 8192 ? 8192 : count
;
227 rpc_get (msock
, RPC_BLOCK
, nbytes
, buf
, RPC_END
);
228 status
= write (handle
, buf
, nbytes
);
230 send_status (status
, errno
);
233 /* FIXED: amount written must be returned to caller */
235 if (status
< nbytes
) {
236 send_status (written
, errno
);
241 send_status (written
, errno
);
247 int handle
, offset
, whence
, status
;
251 RPC_INT
, &offset
, RPC_INT
, &whence
, RPC_END
);
252 status
= lseek (handle
, offset
, whence
);
253 send_status (status
, errno
);
261 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
262 status
= close (handle
);
263 send_status (status
, errno
);
268 /* {{{ Stat family routines */
271 send_time (int sock
, time_t time
)
273 if (clnt_version
== 1) {
278 ct
[3] = ct
[10] = ct
[13] = ct
[16] = ct
[19] = 0;
280 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
285 month
= (ct
[6] == 'n') ? 5 : 6;
286 } else if (ct
[4] == 'F') {
288 } else if (ct
[4] == 'M') {
289 month
= (ct
[6] == 'r') ? 2 : 5;
290 } else if (ct
[4] == 'A') {
291 month
= (ct
[5] == 'p') ? 3 : 7;
292 } else if (ct
[4] == 'S') {
294 } else if (ct
[4] == 'O') {
296 } else if (ct
[4] == 'N') {
300 rpc_send (msock
, RPC_INT
, atoi (&ct
[17]), /* sec */
301 RPC_INT
, atoi (&ct
[14]), /* min */
302 RPC_INT
, atoi (&ct
[11]), /* hour */
303 RPC_INT
, atoi (&ct
[8]), /* mday */
304 RPC_INT
, atoi (&ct
[20]), /* year */
305 RPC_INT
, month
, /* month */
308 long ltime
= (long) time
;
311 snprintf (buf
, sizeof (buf
), "%lx", ltime
);
312 rpc_send (msock
, RPC_STRING
, buf
, RPC_END
);
317 send_stat_info (struct stat
*st
)
321 #ifdef HAVE_ST_BLOCKS
328 mylong
= st
->st_rdev
;
332 rpc_send (msock
, RPC_INT
, (long) mylong
,
333 RPC_INT
, (long) st
->st_ino
,
334 RPC_INT
, (long) st
->st_mode
,
335 RPC_INT
, (long) st
->st_nlink
,
336 RPC_INT
, (long) st
->st_uid
,
337 RPC_INT
, (long) st
->st_gid
,
338 RPC_INT
, (long) st
->st_size
,
339 RPC_INT
, (long) blocks
, RPC_END
);
340 send_time (msock
, st
->st_atime
);
341 send_time (msock
, st
->st_mtime
);
342 send_time (msock
, st
->st_ctime
);
352 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
353 n
= lstat (file
, &st
);
354 send_status (n
, errno
);
356 send_stat_info (&st
);
367 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
368 n
= fstat (handle
, &st
);
369 send_status (n
, errno
);
373 send_stat_info (&st
);
383 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
385 n
= stat (file
, &st
);
386 send_status (n
, errno
);
388 send_stat_info (&st
);
394 /* {{{ Directory lookup operations */
398 DIR *dirs
[OPENDIR_HANDLES
];
399 char *names
[OPENDIR_HANDLES
];
403 close_handle (int handle
)
405 if (mcfs_DIR
.used
> 0)
407 if (mcfs_DIR
.dirs
[handle
])
408 closedir (mcfs_DIR
.dirs
[handle
]);
409 if (mcfs_DIR
.names
[handle
])
410 g_free (mcfs_DIR
.names
[handle
]);
411 mcfs_DIR
.dirs
[handle
] = 0;
412 mcfs_DIR
.names
[handle
] = 0;
422 rpc_get (msock
, RPC_STRING
, &arg
, RPC_END
);
424 if (mcfs_DIR
.used
== OPENDIR_HANDLES
) {
425 send_status (-1, ENFILE
); /* Error */
431 for (i
= 0; i
< OPENDIR_HANDLES
; i
++) {
432 if (mcfs_DIR
.dirs
[i
] == 0) {
439 send_status (-1, EMFILE
);
443 "OOPS! you have found a bug in mc - do_opendir()!\n");
448 printf ("handle=%d\n", handle
);
451 mcfs_DIR
.dirs
[handle
] = p
;
452 mcfs_DIR
.names
[handle
] = arg
;
455 /* Because 0 is an error value */
456 rpc_send (msock
, RPC_INT
, handle
+ 1, RPC_INT
, 0, RPC_END
);
459 send_status (-1, errno
);
464 /* Sends the complete directory listing, as well as the stat information */
468 struct dirent
*dirent
;
472 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
475 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
479 /* We incremented it in opendir */
482 while ((dirent
= readdir (mcfs_DIR
.dirs
[handle
]))) {
485 int length
= NLENGTH (dirent
);
487 rpc_send (msock
, RPC_INT
, length
, RPC_END
);
488 rpc_send (msock
, RPC_BLOCK
, length
, dirent
->d_name
, RPC_END
);
490 strlen (mcfs_DIR
.names
[handle
]) + strlen (dirent
->d_name
) + 2;
491 fname
= malloc (fname_len
);
492 snprintf (fname
, fname_len
, "%s/%s", mcfs_DIR
.names
[handle
],
494 n
= lstat (fname
, &st
);
496 send_status (n
, errno
);
498 send_stat_info (&st
);
500 rpc_send (msock
, RPC_INT
, 0, RPC_END
);
508 rpc_get (msock
, RPC_INT
, &handle
, RPC_END
);
509 close_handle (handle
- 1);
514 /* {{{ Operations with one and two file name argument */
522 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
524 status
= chdir (file
);
525 send_status (status
, errno
);
535 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
537 status
= rmdir (file
);
538 send_status (status
, errno
);
548 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
550 status
= mkdir (file
, mode
);
551 send_status (status
, errno
);
559 int mode
, dev
, status
;
561 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_INT
, &dev
,
564 status
= mknod (file
, mode
, dev
);
565 send_status (status
, errno
);
576 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
577 n
= readlink (file
, buffer
, 2048);
578 send_status (n
, errno
);
581 rpc_send (msock
, RPC_STRING
, buffer
, RPC_END
);
592 rpc_get (msock
, RPC_STRING
, &file
, RPC_END
);
593 status
= unlink (file
);
594 send_status (status
, errno
);
604 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
605 status
= rename (f1
, f2
);
606 send_status (status
, errno
);
617 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
618 status
= symlink (f1
, f2
);
619 send_status (status
, errno
);
630 rpc_get (msock
, RPC_STRING
, &f1
, RPC_STRING
, &f2
, RPC_END
);
631 status
= link (f1
, f2
);
632 send_status (status
, errno
);
640 /* {{{ Misc commands */
645 rpc_send (msock
, RPC_STRING
, (home_dir
) ? home_dir
: "/", RPC_END
);
651 rpc_send (msock
, RPC_STRING
, (up_dir
) ? up_dir
: "/", RPC_END
);
660 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &mode
, RPC_END
);
661 status
= chmod (file
, mode
);
662 send_status (status
, errno
);
670 int owner
, group
, status
;
672 rpc_get (msock
, RPC_STRING
, &file
, RPC_INT
, &owner
, RPC_INT
, &group
,
674 status
= chown (file
, owner
, group
);
675 send_status (status
, errno
);
688 struct utimbuf times
;
690 rpc_get (msock
, RPC_STRING
, &file
,
691 RPC_STRING
, &as
, RPC_STRING
, &ms
, RPC_END
);
692 sscanf (as
, "%lx", &atime
);
693 sscanf (ms
, "%lx", &mtime
);
695 printf ("Got a = %s, m = %s, comp a = %ld, m = %ld\n",
696 as
, ms
, atime
, mtime
);
699 times
.actime
= (time_t) atime
;
700 times
.modtime
= (time_t) mtime
;
701 status
= utime (file
, ×
);
702 send_status (status
, errno
);
720 mc_pam_conversation (int messages
, const struct pam_message
**msg
,
721 struct pam_response
**resp
, void *appdata_ptr
)
723 struct pam_response
*r
;
724 struct user_pass
*up
= appdata_ptr
;
727 r
= (struct pam_response
*) malloc (sizeof (struct pam_response
) *
733 for (status
= PAM_SUCCESS
; messages
--; msg
++, r
++) {
734 switch ((*msg
)->msg_style
) {
736 case PAM_PROMPT_ECHO_ON
:
737 r
->resp
= strdup (up
->username
);
738 r
->resp_retcode
= PAM_SUCCESS
;
741 case PAM_PROMPT_ECHO_OFF
:
742 r
->resp
= strdup (up
->password
);
743 r
->resp_retcode
= PAM_SUCCESS
;
748 r
->resp_retcode
= PAM_SUCCESS
;
753 r
->resp_retcode
= PAM_SUCCESS
;
760 static struct pam_conv conv
= { &mc_pam_conversation
, NULL
};
763 /* Return 0 if authentication failed, 1 otherwise */
765 mc_pam_auth (char *username
, char *password
)
771 up
.username
= username
;
772 up
.password
= password
;
773 conv
.appdata_ptr
= &up
;
776 pam_start ("mcserv", username
, &conv
, &pamh
)) != PAM_SUCCESS
)
778 if ((status
= pam_authenticate (pamh
, 0)) != PAM_SUCCESS
)
780 if ((status
= pam_acct_mgmt (pamh
, 0)) != PAM_SUCCESS
)
782 if ((status
= pam_setcred (pamh
, PAM_ESTABLISH_CRED
)) != PAM_SUCCESS
)
784 pam_end (pamh
, status
);
788 pam_end (pamh
, status
);
792 #else /* Code for non-PAM authentication */
794 /* Keep reading until we find a \n */
796 next_line (int socket
)
801 if (read (socket
, &c
, 1) <= 0)
809 ftp_answer (int sock
, char *text
)
814 socket_read_block (sock
, answer
, 3);
816 if (strcmp (answer
, text
) == 0)
822 send_string (int sock
, char *string
)
824 return socket_write_block (sock
, string
, strlen (string
));
828 do_ftp_auth (char *username
, char *password
)
830 struct sockaddr_in local_address
;
831 unsigned long inaddr
;
835 memset ((char *) &local_address
, 0, sizeof (local_address
));
837 local_address
.sin_family
= AF_INET
;
838 /* FIXME: extract the ftp port with the proper function */
839 local_address
.sin_port
= htons (21);
841 /* Convert localhost to usable format */
842 if ((inaddr
= inet_addr ("127.0.0.1")) != -1)
843 memcpy ((char *) &local_address
.sin_addr
, (char *) &inaddr
,
846 if ((my_socket
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0) {
848 fprintf (stderr
, "do_auth: can't create socket\n");
851 if (connect (my_socket
, (struct sockaddr
*) &local_address
,
852 sizeof (local_address
)) < 0) {
854 "do_auth: can't connect to ftp daemon for authentication\n");
858 send_string (my_socket
, "user ");
859 send_string (my_socket
, username
);
860 send_string (my_socket
, "\r\n");
861 if (!ftp_answer (my_socket
, "331")) {
862 send_string (my_socket
, "quit\r\n");
866 next_line (my_socket
); /* Eat all the line */
867 send_string (my_socket
, "pass ");
868 send_string (my_socket
, password
);
869 send_string (my_socket
, "\r\n");
870 socket_read_block (my_socket
, answer
, 3);
872 send_string (my_socket
, "\r\n");
873 send_string (my_socket
, "quit\r\n");
875 if (strcmp (answer
, "230") == 0)
881 do_classic_auth (char *username
, char *password
)
886 if ((this = getpwnam (username
)) == 0)
890 if (strcmp (crypt (password
, this->pw_passwd
), this->pw_passwd
) == 0) {
900 #endif /* non-PAM authentication */
902 /* Try to authenticate the user based on:
903 - PAM if the system has it, else it checks:
904 - pwdauth if the system supports it.
905 - conventional auth (check salt on /etc/passwd, crypt, and compare
906 - try to contact the local ftp server and login (if -f flag used)
909 do_auth (char *username
, char *password
)
914 if (strcmp (username
, "anonymous") == 0)
918 if (mc_pam_auth (username
, password
) == 0)
920 #else /* if there is no pam */
922 if (pwdauth (username
, password
) == 0)
926 if (do_classic_auth (username
, password
))
929 auth
= do_ftp_auth (username
, password
);
935 this = getpwnam (username
);
939 if (chdir (this->pw_dir
) == -1)
942 if (this->pw_dir
[strlen (this->pw_dir
) - 1] == '/')
943 home_dir
= strdup (this->pw_dir
);
945 home_dir
= malloc (strlen (this->pw_dir
) + 2);
947 strcpy (home_dir
, this->pw_dir
);
948 strcat (home_dir
, "/");
954 if (setgid (this->pw_gid
) == -1)
957 #ifdef HAVE_INITGROUPS
959 if (NGROUPS_MAX
> 1 && initgroups (this->pw_name
, this->pw_gid
))
964 #if defined (HAVE_SETUID)
965 if (setuid (this->pw_uid
))
967 #elif defined (HAVE_SETREUID)
968 if (setreuid (this->pw_uid
, this->pw_uid
))
972 /* If the setuid call failed, then deny access */
973 /* This should fix the problem on those machines with strange setups */
974 if (getuid () != this->pw_uid
)
977 if (strcmp (username
, "ftp") == 0)
978 chroot (this->pw_dir
);
986 do_rauth (int socket
)
988 struct sockaddr_in from
;
991 if (getpeername (0, (struct sockaddr
*) &from
, &fromlen
) < 0)
993 from
.sin_port
= ntohs ((unsigned short) from
.sin_port
);
995 /* Strange, this should not happend */
996 if (from
.sin_family
!= AF_INET
)
999 hp
= gethostbyaddr ((char *) &fromp
.sin_addr
, sizeof (struct in_addr
),
1006 do_rauth (int msock
)
1012 login_reply (int logged_in
)
1014 rpc_send (msock
, RPC_INT
,
1015 logged_in
? MC_LOGINOK
: MC_INVALID_PASS
, RPC_END
);
1018 /* FIXME: Implement the anonymous login */
1026 rpc_get (msock
, RPC_LIMITED_STRING
, &up_dir
, RPC_LIMITED_STRING
,
1027 &username
, RPC_END
);
1029 printf ("username: %s\n", username
);
1032 logged_in
= do_rauth (msock
);
1034 login_reply (logged_in
);
1038 rpc_send (msock
, RPC_INT
, MC_NEED_PASSWORD
, RPC_END
);
1039 rpc_get (msock
, RPC_INT
, &result
, RPC_END
);
1040 if (result
== MC_QUIT
)
1042 if (result
!= MC_PASS
) {
1044 printf ("do_login: Unknown response: %d\n", result
);
1047 rpc_get (msock
, RPC_LIMITED_STRING
, &password
, RPC_END
);
1048 logged_in
= do_auth (username
, password
);
1050 login_reply (logged_in
);
1055 /* {{{ Server and dispatching functions */
1057 /* This structure must be kept in synch with mcfs.h enums */
1059 static struct _command
{
1061 void (*callback
) (void);
1065 "close", do_close
}, {
1067 "write", do_write
}, {
1068 "opendir", do_opendir
}, {
1069 "readdir", do_readdir
}, {
1070 "closedir", do_closedir
}, {
1071 "stat ", do_stat
}, {
1072 "lstat ", do_lstat
}, {
1073 "fstat", do_fstat
}, {
1074 "chmod", do_chmod
}, {
1075 "chown", do_chown
}, {
1076 "readlink ", do_readlink
}, {
1077 "unlink", do_unlink
}, {
1078 "rename", do_rename
}, {
1079 "chdir ", do_chdir
}, {
1080 "lseek", do_lseek
}, {
1081 "rmdir", do_rmdir
}, {
1082 "symlink", do_symlink
}, {
1083 "mknod", do_mknod
}, {
1084 "mkdir", do_mkdir
}, {
1086 "gethome", do_gethome
}, {
1087 "getupdir", do_getupdir
}, {
1088 "login", do_login
}, {
1090 "utime", do_utime
},};
1092 static int ncommands
= sizeof (commands
) / sizeof (struct _command
);
1095 exec_command (int command
)
1098 command
>= ncommands
|| commands
[command
].command
== 0) {
1099 fprintf (stderr
, "Got unknown command: %d\n", command
);
1103 printf ("Command: %s\n", commands
[command
].command
);
1104 (*commands
[command
].callback
) ();
1108 check_version (void)
1112 rpc_get (msock
, RPC_INT
, &version
, RPC_END
);
1113 if (version
>= 1 && version
<= RPC_PROGVER
)
1114 rpc_send (msock
, RPC_INT
, MC_VERSION_OK
, RPC_END
);
1116 rpc_send (msock
, RPC_INT
, MC_VERSION_MISMATCH
, RPC_END
);
1118 clnt_version
= version
;
1121 /* This routine is called by rpc_get/rpc_send when the connection is closed */
1123 tcp_invalidate_socket (int sock
)
1126 printf ("Connection closed\n");
1140 if (rpc_get (sock
, RPC_INT
, &command
, RPC_END
) &&
1141 (logged_in
|| command
== MC_LOGIN
))
1142 exec_command (command
);
1143 } while (!quit_server
);
1148 /* {{{ Net support code */
1151 get_client (int portnum
)
1153 int sock
, clilen
, newsocket
;
1154 struct sockaddr_in client_address
, server_address
;
1157 if ((sock
= socket (AF_INET
, SOCK_STREAM
, 0)) < 0)
1158 return "Cannot create socket";
1160 /* Use this to debug: */
1162 (sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &yes
, sizeof (yes
)) < 0)
1163 return "setsockopt failed";
1165 memset ((char *) &server_address
, 0, sizeof (server_address
));
1166 server_address
.sin_family
= AF_INET
;
1167 server_address
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
1168 server_address
.sin_port
= htons (portnum
);
1170 if (bind (sock
, (struct sockaddr
*) &server_address
,
1171 sizeof (server_address
)) < 0)
1172 return "Cannot bind";
1179 clilen
= sizeof (client_address
);
1180 newsocket
= accept (sock
, (struct sockaddr
*) &client_address
,
1183 if (isDaemon
&& (child
= fork ())) {
1187 waitpid (child
, &status
, 0);
1191 if (isDaemon
&& fork ())
1200 #ifdef HAVE_PMAP_SET
1202 signal_int_handler (int sig
)
1204 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1208 #ifndef IPPORT_RESERVED
1209 #define IPPORT_RESERVED 1024
1213 get_port_number (void)
1217 #ifdef HAVE_RRESVPORT
1218 int start_port
= IPPORT_RESERVED
;
1220 port
= rresvport (&start_port
);
1222 if (geteuid () == 0) {
1224 "Could not bind the server on a reserved port\n");
1225 DO_QUIT_NONVOID (-1);
1233 port
= mcserver_port
;
1239 register_port (int portnum
, int abort_if_fail
)
1241 #ifdef HAVE_PMAP_SET
1242 /* Register our service with the portmapper */
1243 /* protocol: pmap_set (prognum, versnum, protocol, portp) */
1245 if (pmap_set (RPC_PROGNUM
, RPC_PROGVER
, IPPROTO_TCP
, portnum
))
1246 signal (SIGINT
, signal_int_handler
);
1248 fprintf (stderr
, "Could not register service with portmapper\n");
1253 if (abort_if_fail
) {
1255 "This system lacks port registration, try using the -p\n"
1256 "flag to force installation at a given port");
1264 main (int argc
, char *argv
[])
1267 extern char *optarg
;
1270 while ((c
= getopt (argc
, argv
, "fdiqp:v")) != -1) {
1290 portnum
= atoi (optarg
);
1302 fprintf (stderr
, "Usage is: mcserv [options] [-p portnum]\n\n"
1304 "-d become a daemon (sets -q)\n" "-q quiet mode\n"
1305 /* "-r use rhost based authentication\n" */
1307 "-f force ftp authentication\n"
1310 "-p to specify a port number to listen\n");
1316 if (isDaemon
&& fork ())
1320 portnum
= get_port_number ();
1322 if (portnum
!= -1) {
1323 register_port (portnum
, 0);
1325 printf ("Using port %d\n", portnum
);
1326 if ((result
= get_client (portnum
)))
1328 #ifdef HAVE_PMAP_SET
1330 pmap_unset (RPC_PROGNUM
, RPC_PROGVER
);
1336 /* FIXME: This function should not be used in mcserv */