Home | History | Annotate | Line # | Download | only in os
      1 /*
      2  * misc os utilities
      3  */
      4 /*
      5 
      6 Copyright 1990, 1991, 1998  The Open Group
      7 
      8 Permission to use, copy, modify, distribute, and sell this software and its
      9 documentation for any purpose is hereby granted without fee, provided that
     10 the above copyright notice appear in all copies and that both that
     11 copyright notice and this permission notice appear in supporting
     12 documentation.
     13 
     14 The above copyright notice and this permission notice shall be included in
     15 all copies or substantial portions of the Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     20 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 
     24 Except as contained in this notice, the name of The Open Group shall not be
     25 used in advertising or otherwise to promote the sale, use or other dealings
     26 in this Software without prior written authorization from The Open Group.
     27 
     28  * Copyright 1990, 1991 Network Computing Devices;
     29  * Portions Copyright 1987 by Digital Equipment Corporation
     30  *
     31  * Permission to use, copy, modify, distribute, and sell this software and
     32  * its documentation for any purpose is hereby granted without fee, provided
     33  * that the above copyright notice appear in all copies and that both that
     34  * copyright notice and this permission notice appear in supporting
     35  * documentation, and that the names of Network Computing Devices, or Digital
     36  * not be used in advertising or publicity pertaining to distribution
     37  * of the software without specific, written prior permission.
     38  *
     39  * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
     40  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
     41  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
     42  * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     43  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     44  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     45  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
     46  * THIS SOFTWARE.
     47  */
     48 
     49 #include	"config.h"
     50 
     51 #include	<stdio.h>
     52 #include	<X11/Xos.h>
     53 #include	<stdlib.h>
     54 #include	"misc.h"
     55 #include	"globals.h"
     56 #include	<signal.h>
     57 #include	<sys/wait.h>
     58 #include	<unistd.h>
     59 #include	<pwd.h>
     60 #include	<grp.h>
     61 #include	<errno.h>
     62 #include	<sys/types.h>
     63 #include	<errno.h>
     64 #include	<string.h>
     65 #include	"osdep.h"
     66 
     67 #include <stdlib.h>
     68 
     69 static Bool dropPriv = FALSE; /* whether or not to drop root privileges */
     70 #ifdef DEFAULT_DAEMON
     71 static Bool becomeDaemon = TRUE; /* whether to become a daemon or not */
     72 #else
     73 static Bool becomeDaemon = FALSE; /* whether to become a daemon or not */
     74 #endif
     75 #ifdef XFS_INETD
     76 static Bool runFromInetd = FALSE; /* whether we were run from inetd or not */
     77 #endif
     78 static const char *userId = NULL;
     79 char       *progname;
     80 Bool        CloneSelf;
     81 Bool        portFromCmdline = FALSE;
     82 
     83 OldListenRec *OldListen = NULL;
     84 int 	     OldListenCount = 0;
     85 
     86 #ifndef STDERR_FILENO
     87 # define STDERR_FILENO fileno(stderr)
     88 #endif
     89 #define WRITES(s) write(STDERR_FILENO, s, strlen(s))
     90 
     91 static const char *pidFile = XFSPIDDIR "/xfs.pid";
     92 static int  pidFd;
     93 static FILE *pidFilePtr;
     94 static int  StorePid (void);
     95 
     96 /* ARGSUSED */
     97 void
     98 AutoResetServer(int n)
     99 {
    100     int olderrno = errno;
    101 
    102 #ifdef DEBUG
    103     WRITES("got a reset signal\n");
    104 #endif
    105 
    106     dispatchException |= DE_RESET;
    107     isItTimeToYield = TRUE;
    108 
    109     errno = olderrno;
    110 }
    111 
    112 /* ARGSUSED */
    113 void
    114 GiveUp(int n)
    115 {
    116     int olderrno = errno;
    117 #ifdef DEBUG
    118     WRITES("got a TERM signal\n");
    119 #endif
    120 
    121     dispatchException |= DE_TERMINATE;
    122     isItTimeToYield = TRUE;
    123     errno = olderrno;
    124 }
    125 
    126 /* ARGSUSED */
    127 void
    128 ServerReconfig(int n)
    129 {
    130     int olderrno = errno;
    131 
    132 #ifdef DEBUG
    133     WRITES("got a re-config signal\n");
    134 #endif
    135 
    136     dispatchException |= DE_RECONFIG;
    137     isItTimeToYield = TRUE;
    138 
    139     errno = olderrno;
    140 }
    141 
    142 /* ARGSUSED */
    143 void
    144 ServerCacheFlush(int n)
    145 {
    146     int olderrno = errno;
    147 
    148 #ifdef DEBUG
    149     WRITES("got a flush signal\n");
    150 #endif
    151 
    152     dispatchException |= DE_FLUSH;
    153     isItTimeToYield = TRUE;
    154 
    155     errno = olderrno;
    156 }
    157 
    158 /* ARGSUSED */
    159 void
    160 CleanupChild(int n)
    161 {
    162     int olderrno = errno;
    163     pid_t child;
    164 
    165 #ifdef DEBUG
    166     WRITES("got a child signal\n");
    167 #endif
    168 
    169     while ( (child = waitpid((pid_t)-1, NULL, WNOHANG)) > 0 ) {
    170 #ifdef DEBUG
    171 	char msgbuf[64];
    172 
    173 	snprintf(msgbuf, sizeof(msgbuf), " child %d exited\n", child);
    174 	WRITES(msgbuf);
    175 #endif
    176     }
    177 
    178     errno = olderrno;
    179 }
    180 
    181 unsigned int
    182 GetTimeInMillis(void)
    183 {
    184     struct timeval tp;
    185 
    186     X_GETTIMEOFDAY(&tp);
    187     return ((tp.tv_sec * 1000) + (tp.tv_usec / 1000));
    188 }
    189 
    190 static void _X_NORETURN
    191 usage(const char *errmsg)
    192 {
    193     if (errmsg != NULL)
    194         fprintf (stderr, "%s: %s\n", progname, errmsg);
    195     fprintf(stderr, "usage: %s [-config config_file] [-port tcp_port] [-droppriv] [-daemon] [-nodaemon] [-user user_name] [-ls listen_socket]\n"
    196 	    "	    %s [-version]\n",
    197 	    progname, progname);
    198     exit(1);
    199 }
    200 
    201 
    202 /*
    203  * The '-ls' option is used for cloning the font server.
    204  *
    205  * We expect a single string of the form...
    206  *
    207  *     transport_id/fd/portnum[,transport_id/fd/portnum]...
    208  *
    209  * [] denotes optional and ... denotes repetition.
    210  *
    211  * The string must be _exactly_ in the above format.
    212  */
    213 
    214 void
    215 ProcessLSoption (char *str)
    216 {
    217     char *ptr = str;
    218     char *slash;
    219     char number[20];
    220     int count = 0;
    221     int len, i;
    222 
    223     if ((OldListenCount != 0) || (OldListen != NULL)) {
    224         FatalError("-ls may only be specified once\n");
    225     }
    226 
    227     while (*ptr != '\0')
    228     {
    229 	if (*ptr == ',')
    230 	    count++;
    231 	ptr++;
    232     }
    233 
    234     OldListenCount = count + 1;
    235     OldListen = (OldListenRec *) malloc (
    236 	OldListenCount * sizeof (OldListenRec));
    237     if (OldListen == NULL) {
    238 	fprintf(stderr, "ProcessLSoption: malloc error\n");
    239 	exit(1);
    240     }
    241     ptr = str;
    242 
    243     for (i = 0; i < OldListenCount; i++)
    244     {
    245 	slash = (char *) strchr (ptr, '/');
    246 	if (slash == NULL) {
    247 	    usage("invalid argument for -ls");
    248 	}
    249 	len = slash - ptr;
    250 	strncpy (number, ptr, len);
    251 	number[len] = '\0';
    252 	OldListen[i].trans_id = atoi (number);
    253 
    254 	ptr = slash + 1;
    255 
    256 	slash = (char *) strchr (ptr, '/');
    257 	if (slash == NULL) {
    258 	    usage("invalid argument for -ls");
    259 	}
    260 	len = slash - ptr;
    261 	strncpy (number, ptr, len);
    262 	number[len] = '\0';
    263 	OldListen[i].fd = atoi (number);
    264 
    265 	ptr = slash + 1;
    266 
    267 	if (i == OldListenCount - 1)
    268 	    OldListen[i].portnum = atoi (ptr);
    269 	else
    270 	{
    271 	    char *comma = (char *) strchr (ptr, ',');
    272 	    if (comma == NULL) {
    273 		usage("invalid argument for -ls");
    274 	    }
    275 	    len = comma - ptr;
    276 	    strncpy (number, ptr, len);
    277 	    number[len] = '\0';
    278 	    OldListen[i].portnum = atoi (number);
    279 
    280 	    ptr = comma + 1;
    281 	}
    282     }
    283 }
    284 
    285 
    286 
    287 /* ARGSUSED */
    288 void
    289 ProcessCmdLine(int argc, char **argv)
    290 {
    291     int         i;
    292 
    293     progname = argv[0];
    294     for (i = 1; i < argc; i++) {
    295 	if (!strcmp(argv[i], "-port")) {
    296 	    if (argv[i + 1]) {
    297 		ListenPort = atoi(argv[++i]);
    298 		portFromCmdline = TRUE;
    299 	    } else
    300 		usage("-port requires an argument");
    301 	} else if (!strcmp(argv[i], "-ls")) {
    302 	    if (argv[i + 1])
    303 		ProcessLSoption (argv[++i]);
    304 	    else
    305 		usage("-ls requires an argument");
    306 	} else if (!strcmp(argv[i], "-droppriv")) {
    307 	        dropPriv = TRUE;
    308 	} else if (!strcmp(argv[i], "-daemon")) {
    309 	        becomeDaemon = TRUE;
    310 	} else if (!strcmp(argv[i], "-nodaemon")) {
    311 	        becomeDaemon = FALSE;
    312 	} else if (!strcmp(argv[i], "-inetd")) {
    313 #ifdef XFS_INETD
    314 		runFromInetd = TRUE;
    315 #else
    316 		FatalError("-inetd specified, but xfs was not built"
    317 			   " with inetd support\n");
    318 #endif
    319 	} else if (!strcmp(argv[i], "-user")) {
    320 	    if (argv[i + 1])
    321 		userId = argv[++i];
    322 	    else
    323 		usage("-user requires an argument");
    324 	} else if (!strcmp(argv[i], "-cf") || !strcmp(argv[i], "-config")) {
    325 	    if (argv[i + 1])
    326 		configfilename = argv[++i];
    327 	    else
    328 		usage("-config requires an argument");
    329 	}
    330 	else if (!strcmp(argv[i], "-version")) {
    331 	    puts(PACKAGE_STRING);
    332 	    exit(0);
    333 	}
    334 	else {
    335 	    fprintf (stderr, "%s: unrecognized option %s\n", progname, argv[i]);
    336 	    usage(NULL);
    337 	}
    338     }
    339 }
    340 
    341 
    342 #ifndef SPECIAL_MALLOC
    343 
    344 unsigned long	Must_have_memory;
    345 
    346 
    347 /* FSalloc -- FS's internal memory allocator.  Why does it return unsigned
    348  * int * instead of the more common char *?  Well, if you read K&R you'll
    349  * see they say that alloc must return a pointer "suitable for conversion"
    350  * to whatever type you really want.  In a full-blown generic allocator
    351  * there's no way to solve the alignment problems without potentially
    352  * wasting lots of space.  But we have a more limited problem. We know
    353  * we're only ever returning pointers to structures which will have to
    354  * be long word aligned.  So we are making a stronger guarantee.  It might
    355  * have made sense to make FSalloc return char * to conform with people's
    356  * expectations of malloc, but this makes lint happier.
    357  */
    358 
    359 pointer
    360 FSalloc (unsigned long amount)
    361 {
    362     register pointer  ptr;
    363 
    364     if ((long)amount < 0)
    365 	return 0;
    366     if (amount == 0)
    367 	amount++;
    368     /* aligned extra on long word boundary */
    369     amount = (amount + 3) & ~3;
    370     if ((ptr = (pointer)malloc(amount)) != 0)
    371 	return ptr;
    372     if (Must_have_memory)
    373 	FatalError("out of memory\n");
    374     return 0;
    375 }
    376 
    377 /* FSallocarray: Array allocation with overflow check */
    378 
    379 pointer
    380 FSallocarray (unsigned long num, unsigned long size)
    381 {
    382     if (num != 0 && size != 0) {
    383         if (size > (SIZE_MAX / num)) {
    384             return NULL;
    385         }
    386     }
    387     return FSalloc(num * size);
    388 }
    389 
    390 /*****************
    391  * FScalloc
    392  *****************/
    393 
    394 pointer
    395 FScalloc (unsigned long num, unsigned long size)
    396 {
    397     pointer ret;
    398 
    399     ret = FSallocarray(num, size);
    400     if (ret)
    401 	memset (ret, 0, num * size);
    402     return ret;
    403 }
    404 
    405 /*****************
    406  * FSrealloc
    407  *****************/
    408 
    409 pointer
    410 FSrealloc (pointer ptr, unsigned long amount)
    411 {
    412     if ((long)amount <= 0)
    413     {
    414 	if (ptr && !amount)
    415 	    free(ptr);
    416 	return 0;
    417     }
    418     amount = (amount + 3) & ~3;
    419     if (ptr)
    420         ptr = (pointer)realloc((char *)ptr, amount);
    421     else
    422 	ptr = (pointer)malloc(amount);
    423     if (ptr)
    424         return ptr;
    425     if (Must_have_memory)
    426 	FatalError("out of memory\n");
    427     return 0;
    428 }
    429 
    430 /* FSreallocarray: Array reallocation with overflow check */
    431 
    432 pointer
    433 FSreallocarray (pointer ptr, unsigned long num, unsigned long size)
    434 {
    435     if (num != 0 && size != 0) {
    436         if (size > (SIZE_MAX / num)) {
    437             return NULL;
    438         }
    439     }
    440     return FSrealloc(ptr, num * size);
    441 }
    442 
    443 
    444 /*****************
    445  *  FSfree
    446  *    calls free
    447  *****************/
    448 
    449 void
    450 FSfree(pointer ptr)
    451 {
    452     if (ptr)
    453 	free((char *)ptr);
    454 }
    455 
    456 #endif /* SPECIAL_MALLOC */
    457 
    458 
    459 void
    460 SetUserId(void)
    461 {
    462     /* become xfs user (or other specified on command line) if possible */
    463     if ((geteuid() == 0) && (dropPriv || userId)) {
    464 	const char *user;
    465 	struct passwd *pwent;
    466 
    467 	if (!userId)
    468 	    user = "xfs";
    469 	else
    470 	    user = userId;
    471 	pwent = getpwnam(user);
    472 	if (pwent) {
    473 	    if (setgid(pwent->pw_gid)) {
    474 		FatalError("fatal: couldn't set groupid to xfs user's group\n");
    475 	    }
    476 #ifndef __CYGWIN__
    477 	    if (setgroups(0, NULL)) {
    478 		FatalError("fatal: couldn't drop supplementary groups\n");
    479 	    }
    480 #endif
    481 	    if (initgroups(user, pwent->pw_gid)) {
    482 		FatalError("fatal: couldn't init supplementary groups\n");
    483 	    }
    484 	    if (setuid(pwent->pw_uid)) {
    485 		FatalError("fatal: couldn't set userid to %s user\n", user);
    486 	    }
    487 	}
    488     } else if (dropPriv || userId) {
    489 	FatalError("fatal: -droppriv or -user flag specified, but xfs not run as root\n");
    490     }
    491 }
    492 
    493 
    494 void
    495 SetDaemonState(void)
    496 {
    497     int	    oldpid;
    498 
    499 #ifdef XFS_INETD
    500     if (runFromInetd) {
    501 	int inetdListener;
    502 
    503 	/* fd's 0, 1, & 2 are the initial listen socket provided by inetd,
    504 	 * so dup it and then clear them so stdin/out/err aren't in use.
    505 	 */
    506 	inetdListener = dup(0);
    507 	if (inetdListener == -1) {
    508 	    FatalError("failed to dup inetd socket: %s\n",
    509 		       strerror(errno));
    510 	}
    511 	DetachStdio();
    512 
    513 	/* Setup & pass the inetd socket back through the connection setup
    514 	 * code the same way as a cloned listening port
    515 	 */
    516 	OldListenCount = 1;
    517 	OldListen = _FontTransGetInetdListenInfo (inetdListener);
    518 	if (OldListen == NULL) {
    519 	    FatalError("failed to initialize OldListen to inetd socket: %s\n",
    520 		       strerror(errno));
    521 	}
    522 	ListenPort = OldListen[0].portnum;
    523 	NoticeF("accepting listener from inetd on fd %d, port %d\n",
    524 		inetdListener, ListenPort);
    525 	return;
    526     }
    527 #endif /* XFS_INETD */
    528 
    529     if (becomeDaemon) {
    530 	BecomeDaemon();
    531 	if ((oldpid = StorePid ())) {
    532 	    if (oldpid == -1)
    533 		ErrorF ("error opening process-id file %s\n", pidFile);
    534 	    else
    535 		ErrorF ("process-id file %s indicates another xfs is "
    536 			  "running (pid %d); exiting\n", pidFile, oldpid);
    537 	    exit(1);
    538 	}
    539     }
    540 }
    541 
    542 
    543 static int
    544 StorePid (void)
    545 {
    546     int		oldpid;
    547 
    548     if (pidFile[0] != '\0') {
    549 	pidFd = open (pidFile, O_RDWR);
    550 	if (pidFd == -1 && errno == ENOENT)
    551 	    pidFd = open (pidFile, O_RDWR|O_CREAT, 0666);
    552 	if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
    553 	{
    554 	    ErrorF ("cannot open process-id file %s: %s\n", pidFile,
    555 		    strerror (errno));
    556 	    return -1;
    557 	}
    558 	if (fscanf (pidFilePtr, "%d\n", &oldpid) != 1)
    559 	    oldpid = -1;
    560 	if (fseek (pidFilePtr, 0L, SEEK_SET) == -1)
    561 	{
    562 	    ErrorF ("cannot seek process-id file %s: %s\n", pidFile,
    563 		     strerror (errno));
    564 	    return -1;
    565 	}
    566 	if (fprintf (pidFilePtr, "%11ld\n", (long) getpid ()) != 12)
    567 	{
    568 	    ErrorF ("cannot write to process-id file %s: %s\n", pidFile,
    569 		    strerror (errno));
    570 	    return -1;
    571 	}
    572 	(void) fflush (pidFilePtr);
    573 	(void) fclose (pidFilePtr);
    574     }
    575     return 0;
    576 }
    577 
    578 static const unsigned char _reverse_byte[0x100] = {
    579 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    580 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    581 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    582 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    583 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    584 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    585 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    586 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    587 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    588 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    589 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    590 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    591 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    592 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    593 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    594 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    595 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    596 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    597 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    598 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    599 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    600 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    601 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    602 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    603 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    604 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    605 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    606 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    607 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    608 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    609 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    610 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
    611 };
    612 
    613 /*
    614  *	Invert bit order within each BYTE of an array.
    615  */
    616 void
    617 BitOrderInvert(unsigned char *buf, int nbytes)
    618 {
    619     const unsigned char *rev = _reverse_byte;
    620 
    621     for (; --nbytes >= 0; buf++)
    622 	*buf = rev[*buf];
    623 }
    624 
    625 /*
    626  *	Invert byte order within each 16-bits of an array.
    627  */
    628 void
    629 TwoByteSwap(unsigned char *buf, int nbytes)
    630 {
    631     unsigned char c;
    632 
    633     for (; nbytes > 0; nbytes -= 2, buf += 2)
    634     {
    635 	c = buf[0];
    636 	buf[0] = buf[1];
    637 	buf[1] = c;
    638     }
    639 }
    640 
    641 /*
    642  *	Invert byte order within each 32-bits of an array.
    643  */
    644 void
    645 FourByteSwap(unsigned char *buf, int nbytes)
    646 {
    647     unsigned char c;
    648 
    649     for (; nbytes > 0; nbytes -= 4, buf += 4)
    650     {
    651 	c = buf[0];
    652 	buf[0] = buf[3];
    653 	buf[3] = c;
    654 	c = buf[1];
    655 	buf[1] = buf[2];
    656 	buf[2] = c;
    657     }
    658 }
    659 
    660