2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
14 #include <afs/procmgmt.h>
19 #include <WINNT/afsevent.h>
23 #include <sys/statfs.h>
29 #include <afs/cellconfig.h>
30 #include <afs/afsutil.h>
31 #include <afs/fileutil.h>
32 #include <afs/com_err.h>
37 static int AddObject(char **expPath
, char *dir
);
38 static int PathInDirectory(char *dir
, char *path
);
39 int update_SendFile(int, struct rx_call
*, struct stat
*);
40 int update_SendDirInfo(char *, struct rx_call
*, struct stat
*,
43 struct afsconf_dir
*cdir
;
45 char *dirName
[MAXENTRIES
];
46 int dirLevel
[MAXENTRIES
];
49 static int Quit(char *);
53 #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
54 afs_uint32 SHostAddrs
[ADDRSPERSITE
];
56 /* check whether caller is authorized to manage RX statistics */
58 update_rxstat_userok(struct rx_call
*call
)
60 return afsconf_SuperUser(cdir
, call
, NULL
);
64 * PathInDirectory() -- determine if path is in directory (or is directory)
65 * Returns 1 if yes, 0 if no, -1 on error.
68 PathInDirectory(char *dir
, char *path
)
72 char *dirNorm
, *pathNorm
;
75 /* case-insensitive comparison of normalized, same-flavor (short) paths */
78 dirNorm
= malloc(AFSDIR_PATH_MAX
);
81 status
= GetShortPathName(dir
, dirNorm
, AFSDIR_PATH_MAX
);
82 if (status
== 0 || status
> AFSDIR_PATH_MAX
) {
83 /* can't convert path to short version; just use long version */
85 dirNorm
= strdup(dir
);
89 FilepathNormalize(dirNorm
);
91 pathNorm
= malloc(AFSDIR_PATH_MAX
);
92 if (pathNorm
== NULL
) {
96 status
= GetShortPathName(path
, pathNorm
, AFSDIR_PATH_MAX
);
97 if (status
== 0 || status
> AFSDIR_PATH_MAX
) {
98 /* can't convert path to short version; just use long version */
100 pathNorm
= strdup(path
);
101 if (pathNorm
== NULL
) {
106 FilepathNormalize(pathNorm
);
108 dirLen
= strlen(dirNorm
);
110 if (_strnicmp(dirNorm
, pathNorm
, dirLen
) == 0) {
111 /* substrings match; path must match dir or be subdirectory */
112 if (pathNorm
[dirLen
] == '\0' || pathNorm
[dirLen
] == '/') {
117 /* case-sensitive comparison of normalized paths */
118 dirNorm
= strdup(dir
);
121 FilepathNormalize(dirNorm
);
123 pathNorm
= strdup(path
);
124 if (pathNorm
== NULL
) {
128 FilepathNormalize(pathNorm
);
130 dirLen
= strlen(dirNorm
);
132 if (strncmp(dirNorm
, pathNorm
, dirLen
) == 0) {
133 /* substrings match; path must match dir or be subdirectory */
134 if (pathNorm
[dirLen
] == '\0' || pathNorm
[dirLen
] == '/') {
138 #endif /* AFS_NT40_ENV */
143 return (code
!= 0) ? code
: inDir
;
147 AuthOkay(struct rx_call
*call
, char *name
)
154 /* Must be in 'UserList' to use */
155 if (!afsconf_SuperUser(cdir
, call
, NULL
))
158 if (rx_SecurityClassOf(rx_ConnectionOf(call
)) == RX_SECIDX_KAD
) {
159 code
= rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, 0, 0, 0, 0, 0);
166 for (i
= 0; i
< nDirs
; i
++) {
167 r
= PathInDirectory(dirName
[i
], name
);
171 if (dirLevel
[i
] > level
)
174 /* keep searching in case there's a more restrictive subtree
175 * specified later. */
178 if (nDirs
&& !matches
)
179 return 0; /* if dirs spec., name must match */
180 return 1; /* okay or no dirs */
186 /* this sucks but it works for now.
192 #include "AFS_component_version_number.c"
196 main(int argc
, char *argv
[])
198 struct rx_securityClass
**securityClasses
;
199 afs_int32 numClasses
;
200 struct rx_service
*service
;
201 afs_uint32 host
= htonl(INADDR_ANY
);
205 rxkad_level newLevel
;
209 * The following signal action for AIX is necessary so that in case of a
210 * crash (i.e. core is generated) we can include the user's data section
211 * in the core dump. Unfortunately, by default, only a partial core is
212 * generated which, in many cases, isn't too useful.
214 struct sigaction nsa
;
216 sigemptyset(&nsa
.sa_mask
);
217 nsa
.sa_handler
= SIG_DFL
;
218 nsa
.sa_flags
= SA_FULLDUMP
;
219 sigaction(SIGABRT
, &nsa
, NULL
);
220 sigaction(SIGSEGV
, &nsa
, NULL
);
226 /* dummy signal call to force afsprocmgmt.dll to load on NT */
227 signal(SIGUSR1
, SIG_DFL
);
230 /* Initialize dirpaths */
231 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK
)) {
233 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR
, 0, argv
[0], 0);
235 fprintf(stderr
, "%s: Unable to obtain AFS server directory.\n",
242 if (argc
== 1) /* no arguments */
245 /* support help flag */
246 if (strcmp("-help", argv
[1]) == 0)
248 if (strcmp("help", argv
[1]) == 0)
251 for (a
= 1; a
< argc
; a
++) {
252 if (argv
[a
][0] == '-') { /* parse options */
253 if (strcmp(argv
[a
], "-rxbind") == 0) {
258 lcstring(arg
, argv
[a
], sizeof(arg
));
259 newLevel
= rxkad_StringToLevel(&argv
[a
][1]);
260 if (newLevel
!= -1) {
261 level
= newLevel
; /* set new level */
266 Quit("Usage: upserver [<directory>+] [-crypt <directory>+] [-clear <directory>+] [-auth <directory>+] [-rxbind] [-help]\n");
268 if (nDirs
>= sizeof(dirName
) / sizeof(dirName
[0]))
269 Quit("Too many dirs");
270 if (AddObject(&dirName
[nDirs
], argv
[a
])) {
271 printf("%s: Unable to export dir %s. Skipping\n", whoami
,
275 dirLevel
[nDirs
] = level
; /* remember current level */
280 if (nDirs
== 0) { /* Didn't find any directories to export */
281 printf("%s: No directories to export. Quitting\n", whoami
);
285 cdir
= afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH
);
287 fprintf(stderr
, "Can't get server configuration info (%s)\n",
288 AFSDIR_SERVER_ETC_DIRPATH
);
294 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH
||
295 AFSDIR_SERVER_NETINFO_FILEPATH
) {
297 ccode
= afsconf_ParseNetFiles(SHostAddrs
, NULL
, NULL
,
298 ADDRSPERSITE
, reason
,
299 AFSDIR_SERVER_NETINFO_FILEPATH
,
300 AFSDIR_SERVER_NETRESTRICT_FILEPATH
);
303 ccode
= rx_getAllAddr(SHostAddrs
, ADDRSPERSITE
);
306 host
= SHostAddrs
[0];
309 /* Initialize Rx, telling it port number this server will use for its
311 if (rx_InitHost(host
, htons(AFSCONF_UPDATEPORT
)) < 0)
314 afsconf_BuildServerSecurityObjects(cdir
, &securityClasses
, &numClasses
);
316 if (securityClasses
[2] == NULL
)
317 Quit("rxkad_NewServerSecurityObject");
319 /* Instantiate a single UPDATE service. The rxgen-generated procedure
320 * which is called to decode requests is passed in here
321 * (UPDATE_ExecuteRequest). */
323 rx_NewServiceHost(host
, 0, UPDATE_SERVICEID
, "UPDATE", securityClasses
,
324 numClasses
, UPDATE_ExecuteRequest
);
325 if (service
== (struct rx_service
*)0)
326 Quit("rx_NewService");
327 rx_SetMaxProcs(service
, 2);
329 /* allow super users to manage RX statistics */
330 rx_SetRxStatUserOk(update_rxstat_userok
);
332 rx_StartServer(1); /* Donate this process to the server process pool */
333 Quit("StartServer returned?");
337 /* fetch the file name and send it to the remote requester specified by call */
340 UPDATE_FetchFile(struct rx_call
*call
, char *name
)
347 /* construct a local path from a canonical (wire-format) path */
348 if ((error
= ConstructLocalPath(name
, "/", &reqObject
))) {
349 afs_com_err(whoami
, error
, "Unable to construct local path");
353 if (!AuthOkay(call
, reqObject
)) {
354 error
= UPDATE_ERROR
;
356 fd
= open(reqObject
, O_RDONLY
, 0);
357 if (fd
< 0 || fstat(fd
, &status
) < 0) {
358 printf("Failed to open %s\n", reqObject
);
359 error
= UPDATE_ERROR
;
362 error
= update_SendFile(fd
, call
, &status
);
370 /* fetch dir info about directory name and send it to remote host associated
373 UPDATE_FetchInfo(struct rx_call
*call
, char *name
)
379 /* construct a local path from a canonical (wire-format) path */
380 if ((error
= ConstructLocalPath(name
, "/", &reqObject
))) {
381 afs_com_err(whoami
, error
, "Unable to construct local path");
385 if (!AuthOkay(call
, reqObject
)) {
386 error
= UPDATE_ERROR
;
388 /* we only need to stat the obj, not open it. */
389 if (stat(reqObject
, &status
) < 0) {
390 printf("Failed to open %s\n", reqObject
);
391 error
= UPDATE_ERROR
;
393 if ((status
.st_mode
& S_IFMT
) != S_IFDIR
) {
394 printf(" file %s is not a directory \n", reqObject
);
399 error
= update_SendDirInfo(reqObject
, call
, &status
, name
);
408 fprintf(stderr
, "%s", msg
);
413 update_SendFile(int fd
, struct rx_call
*call
, struct stat
*status
)
415 char *buffer
= (char *)0;
417 afs_int32 length
, tlen
;
419 struct statfs tstatfs
;
424 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
425 fstatfs(fd
, &tstatfs
);
426 blockSize
= tstatfs
.f_bsize
;
430 blockSize
= status
->st_blksize
;
432 length
= status
->st_size
;
433 buffer
= malloc(blockSize
);
435 printf("malloc failed\n");
438 tlen
= htonl(length
);
439 rx_Write(call
, (char *)&tlen
, sizeof(afs_int32
)); /* send length on fetch */
440 while (!error
&& length
) {
441 int nbytes
= (length
> blockSize
? blockSize
: length
);
442 nbytes
= read(fd
, buffer
, nbytes
);
444 fprintf(stderr
, "File system read failed\n");
447 if (rx_Write(call
, buffer
, nbytes
) != nbytes
)
454 error
= UPDATE_ERROR
;
458 /* Enumerate dir (name) and write dir entry info into temp file.
461 update_SendDirInfo(char *name
, /* Name of dir to enumerate */
462 struct rx_call
*call
, /* rx call */
463 struct stat
*status
, /* stat struct for dir */
464 char *origDir
) /* orig name of dir before being localized */
470 char filename
[MAXFNSIZE
], dirInfoFile
[MAXFNSIZE
];
471 int fd
, tfd
, errcode
, error
, err
;
474 dirp
= opendir(name
);
475 sprintf(dirInfoFile
, "%s/upserver.tmp", gettmpdir());
476 stream
= fopen(dirInfoFile
, "w");
480 while ((dp
= readdir(dirp
))) {
481 strcpy(filename
, name
);
482 strcat(filename
, "/");
483 strcat(filename
, dp
->d_name
);
485 tfd
= open(filename
, O_RDONLY
, 0);
486 if (tfd
< 0 || fstat(tfd
, &tstatus
) < 0) {
487 printf("Failed to open %s\n", name
);
488 error
= UPDATE_ERROR
;
491 if ((tstatus
.st_mode
& S_IFMT
) != S_IFDIR
) { /* not a directory */
492 char dirEntry
[MAXFNSIZE
];
494 strcpy(dirEntry
, origDir
);
495 strcat(dirEntry
, "/");
496 strcat(dirEntry
, dp
->d_name
);
498 fprintf(stream
, "\"%s\" %u %u %u %u %u %u\n", dirEntry
,
499 (unsigned int)tstatus
.st_mtime
,
500 (unsigned int)tstatus
.st_size
, tstatus
.st_mode
,
501 tstatus
.st_uid
, tstatus
.st_gid
,
502 (unsigned int)tstatus
.st_atime
);
508 printf("could not close file %s \n", filename
);
509 error
= UPDATE_ERROR
;
520 error
= UPDATE_ERROR
;
524 fd
= open(dirInfoFile
, O_RDONLY
, 0);
527 errcode
= update_SendFile(fd
, call
, &tstatus
);
530 error
= UPDATE_ERROR
;
539 /* AddObject() - Adds the object to the list of exported objects after
540 * converting to a local path.
542 * expPath : points to allocated storage in which the exportable path is
544 * dir : dir name passed in for export
548 AddObject(char **expPath
, char *dir
)
553 /* construct a local path from a canonical (wire-format) path */
554 if ((error
= ConstructLocalPath(dir
, "/", expPath
))) {
555 afs_com_err(whoami
, error
, "Unable to construct local path");
559 /* stat the object */
560 error
= stat(*expPath
, &statbuf
);
562 afs_com_err(whoami
, error
, ";Can't stat object.");
565 /* now check if the object has an exportable (file/dir) type */
566 if (!(statbuf
.st_mode
& S_IFDIR
)) {
567 fprintf(stderr
, "%s: Unacceptable object type for %s\n", whoami
,