fix include file case
[reactos.git] / rosapps / mc / src / utilunix.c
1 /* Various utilities - Unix variants
2 Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
3 Written 1994, 1995, 1996 by:
4 Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
5 Jakub Jelinek, Mauricio Plaza.
6
7 The file_date routine is mostly from GNU's fileutils package,
8 written by Richard Stallman and David MacKenzie.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
23
24 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <fcntl.h>
32 #include <signal.h> /* my_system */
33 #include <limits.h> /* INT_MAX */
34 #include <sys/time.h> /* select: timeout */
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <stdarg.h>
39 #ifdef HAVE_SYS_WAIT_H
40 # include <sys/wait.h> /* my_system */
41 #endif
42 #include <errno.h> /* my_system */
43 #include <pwd.h>
44 #include <grp.h>
45 #include <string.h>
46 #include <ctype.h>
47 #ifdef HAVE_SYS_SELECT_H
48 # include <sys/select.h>
49 #endif
50 #ifdef SCO_FLAVOR
51 # include <sys/timeb.h>
52 #endif
53 #include <time.h>
54 #ifdef __linux__
55 # if defined(__GLIBC__) && (__GLIBC__ < 2)
56 # include <linux/termios.h> /* This is needed for TIOCLINUX */
57 # else
58 # include <termios.h>
59 # endif
60 # include <sys/ioctl.h>
61 #endif
62 #ifdef __QNX__
63 # include <unix.h> /* exec*() from <process.h> */
64 #endif
65 #include "util.h"
66 #include "global.h"
67 #include "fsusage.h"
68 #include "fsusage.h"
69 #include "mountlist.h"
70 #include "mad.h"
71 #include "dialog.h" /* message() */
72 #include "../vfs/vfs.h" /* mc_read() */
73 #include "x.h"
74
75 struct sigaction startup_handler;
76 extern struct mount_entry *mount_list;
77
78 uid_t current_user_uid;
79 user_in_groups *current_user_gid;
80
81 int
82 max_open_files (void)
83 {
84 static int files;
85
86 if (files)
87 return files;
88
89 #ifdef HAVE_SYSCONF
90 files = sysconf (_SC_OPEN_MAX);
91 if (files != -1)
92 return files;
93 #endif
94 #ifdef OPEN_MAX
95 return files = OPEN_MAX;
96 #else
97 return files = 256;
98 #endif
99 }
100
101 void init_groups (void)
102 {
103 int i;
104 struct passwd *pwd;
105 struct group *grp;
106 user_in_groups *cug, *pug;
107
108 pwd = getpwuid (current_user_uid=getuid ());
109
110 current_user_gid = (pug = xmalloc (sizeof (user_in_groups), "init_groups"));
111 current_user_gid->gid = getgid (); current_user_gid->next = 0;
112
113 if (pwd == 0)
114 return;
115
116 setgrent ();
117 while ((grp = getgrent ()))
118 for (i = 0; grp->gr_mem[i]; i++)
119 if (!strcmp (pwd->pw_name,grp->gr_mem[i]))
120 {
121 cug = xmalloc (sizeof (user_in_groups), "init_groups");
122 cug->gid = grp->gr_gid;
123 pug->next = cug;
124 cug->next = 0;
125 pug = cug;
126 break;
127 }
128 endgrent ();
129 }
130
131 /* Return the index of permission triplet */
132 int
133 get_user_rights (struct stat *buf)
134 {
135 user_in_groups *cug;
136
137 if (buf->st_uid == current_user_uid || current_user_uid == 0)
138 return 0;
139
140 for (cug = current_user_gid; cug; cug = cug->next)
141 if (cug->gid == buf->st_gid) return 1;
142
143 return 2;
144 }
145
146
147 void
148 delete_groups (void)
149 {
150 user_in_groups *pug, *cug = current_user_gid;
151
152 while (cug){
153 pug = cug->next;
154 free (cug);
155 cug = pug;
156 }
157 }
158
159 #define UID_CACHE_SIZE 200
160 #define GID_CACHE_SIZE 30
161
162 typedef struct {
163 int index;
164 char *string;
165 } int_cache;
166
167 int_cache uid_cache [UID_CACHE_SIZE];
168 int_cache gid_cache [GID_CACHE_SIZE];
169
170 void init_uid_gid_cache (void)
171 {
172 int i;
173
174 for (i = 0; i < UID_CACHE_SIZE; i++)
175 uid_cache [i].string = 0;
176
177 for (i = 0; i < GID_CACHE_SIZE; i++)
178 gid_cache [i].string = 0;
179 }
180
181 static char *i_cache_match (int id, int_cache *cache, int size)
182 {
183 int i;
184
185 for (i = 0; i < size; i++)
186 if (cache [i].index == id)
187 return cache [i].string;
188 return 0;
189 }
190
191 static void i_cache_add (int id, int_cache *cache, int size, char *text,
192 int *last)
193 {
194 if (cache [*last].string)
195 free (cache [*last].string);
196 cache [*last].string = strdup (text);
197 cache [*last].index = id;
198 *last = ((*last)+1) % size;
199 }
200
201 char *get_owner (int uid)
202 {
203 struct passwd *pwd;
204 static char ibuf [8];
205 char *name;
206 static int uid_last;
207
208 if ((name = i_cache_match (uid, uid_cache, UID_CACHE_SIZE)) != NULL)
209 return name;
210
211 pwd = getpwuid (uid);
212 if (pwd){
213 i_cache_add (uid, uid_cache, UID_CACHE_SIZE, pwd->pw_name, &uid_last);
214 return pwd->pw_name;
215 }
216 else {
217 sprintf (ibuf, "%d", uid);
218 return ibuf;
219 }
220 }
221
222 char *get_group (int gid)
223 {
224 struct group *grp;
225 static char gbuf [8];
226 char *name;
227 static int gid_last;
228
229 if ((name = i_cache_match (gid, gid_cache, GID_CACHE_SIZE)) != NULL)
230 return name;
231
232 grp = getgrgid (gid);
233 if (grp){
234 i_cache_add (gid, gid_cache, GID_CACHE_SIZE, grp->gr_name, &gid_last);
235 return grp->gr_name;
236 } else {
237 sprintf (gbuf, "%d", gid);
238 return gbuf;
239 }
240 }
241
242 /* Since ncurses uses a handler that automatically refreshes the */
243 /* screen after a SIGCONT, and we don't want this behavior when */
244 /* spawning a child, we save the original handler here */
245 void save_stop_handler (void)
246 {
247 sigaction (SIGTSTP, NULL, &startup_handler);
248 }
249
250 #ifdef HAVE_GNOME
251 #define PORT_HAS_MY_SYSTEM 1
252 #endif
253
254 #ifndef PORT_HAS_MY_SYSTEM
255 int my_system (int flags, const char *shell, const char *command)
256 {
257 struct sigaction ignore, save_intr, save_quit, save_stop;
258 pid_t pid;
259 int status = 0;
260 int as_shell_command = flags & EXECUTE_AS_SHELL;
261
262 ignore.sa_handler = SIG_IGN;
263 sigemptyset (&ignore.sa_mask);
264 ignore.sa_flags = 0;
265
266 sigaction (SIGINT, &ignore, &save_intr);
267 sigaction (SIGQUIT, &ignore, &save_quit);
268
269 /* Restore the original SIGTSTP handler, we don't want ncurses' */
270 /* handler messing the screen after the SIGCONT */
271 sigaction (SIGTSTP, &startup_handler, &save_stop);
272
273 if ((pid = fork ()) < 0){
274 fprintf (stderr, "\n\nfork () = -1\n");
275 return -1;
276 }
277 if (pid == 0){
278 sigaction (SIGINT, &save_intr, NULL);
279 sigaction (SIGQUIT, &save_quit, NULL);
280
281 #if 0
282 prepare_environment ();
283 #endif
284
285 if (as_shell_command)
286 execl (shell, shell, "-c", command, (char *) 0);
287 else
288 execlp (shell, shell, command, (char *) 0);
289
290 _exit (127); /* Exec error */
291 } else {
292 while (waitpid (pid, &status, 0) < 0)
293 if (errno != EINTR){
294 status = -1;
295 break;
296 }
297 }
298 sigaction (SIGINT, &save_intr, NULL);
299 sigaction (SIGQUIT, &save_quit, NULL);
300 sigaction (SIGTSTP, &save_stop, NULL);
301
302 #ifdef SCO_FLAVOR
303 waitpid(-1, NULL, WNOHANG);
304 #endif /* SCO_FLAVOR */
305
306 return WEXITSTATUS(status);
307 }
308 #endif
309
310 /* Returns a newly allocated string, if directory does not exist, return 0 */
311 char *tilde_expand (char *directory)
312 {
313 struct passwd *passwd;
314 char *p;
315 char *name;
316 int len;
317
318 if (*directory != '~')
319 return strdup (directory);
320
321 directory++;
322
323 p = strchr (directory, PATH_SEP);
324
325 /* d = "~" or d = "~/" */
326 if (!(*directory) || (*directory == PATH_SEP)){
327 passwd = getpwuid (geteuid ());
328 p = (*directory == PATH_SEP) ? directory+1 : "";
329 } else {
330 if (!p){
331 p = "";
332 passwd = getpwnam (directory);
333 } else {
334 name = xmalloc (p - directory + 1, "tilde_expand");
335 strncpy (name, directory, p - directory);
336 name [p - directory] = 0;
337 passwd = getpwnam (name);
338 free (name);
339 }
340 }
341
342 /* If we can't figure the user name, return NULL */
343 if (!passwd)
344 return 0;
345
346 len = strlen (passwd->pw_dir) + strlen (p) + 2;
347 directory = xmalloc (len, "tilde_expand");
348 strcpy (directory, passwd->pw_dir);
349 strcat (directory, PATH_SEP_STR);
350 strcat (directory, p);
351 return directory;
352 }
353
354 int
355 set_nonblocking (int fd)
356 {
357 int val;
358
359 val = fcntl (fd, F_GETFL, 0);
360 val |= O_NONBLOCK;
361 return fcntl (fd, F_SETFL, val) != -1;
362 }
363
364 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
365 /* More than that would be unportable */
366 #define MAX_PIPE_SIZE 4096
367
368 static int error_pipe[2]; /* File descriptors of error pipe */
369 static int old_error; /* File descriptor of old standard error */
370
371 /* Creates a pipe to hold standard error for a later analysis. */
372 /* The pipe can hold 4096 bytes. Make sure no more is written */
373 /* or a deadlock might occur. */
374 void open_error_pipe (void)
375 {
376 if (pipe (error_pipe) < 0){
377 message (0, _(" Warning "), _(" Pipe failed "));
378 }
379 old_error = dup (2);
380 if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
381 message (0, _(" Warning "), _(" Dup failed "));
382 close (error_pipe[0]);
383 close (error_pipe[1]);
384 }
385 close (error_pipe[1]);
386 }
387
388 void close_error_pipe (int error, char *text)
389 {
390 char *title;
391 char msg[MAX_PIPE_SIZE];
392 int len = 0;
393
394 if (error)
395 title = MSG_ERROR;
396 else
397 title = " Warning ";
398 if (old_error >= 0){
399 close (2);
400 dup (old_error);
401 close (old_error);
402 len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
403
404 if (len >= 0)
405 msg[len] = 0;
406 close (error_pipe[0]);
407 }
408 if (error < 0)
409 return; /* Just ignore error message */
410 if (text == NULL){
411 if (len == 0) return; /* Nothing to show */
412
413 /* Show message from pipe */
414 message (error, title, msg);
415 } else {
416 /* Show given text and possible message from pipe */
417 message (error, title, " %s \n %s ", text, msg);
418 }
419 }
420
421 /* Checks for messages in the error pipe,
422 * closes the pipe and displays an error box if needed
423 */
424 void check_error_pipe (void)
425 {
426 char error[MAX_PIPE_SIZE];
427 int len = 0;
428 if (old_error >= 0){
429 while (len < MAX_PIPE_SIZE)
430 {
431 fd_set select_set;
432 struct timeval timeout;
433 FD_ZERO (&select_set);
434 FD_SET (error_pipe[0], &select_set);
435 timeout.tv_sec = 0;
436 timeout.tv_usec = 0;
437 select (FD_SETSIZE, &select_set, 0, 0, &timeout);
438 if (!FD_ISSET (0, &select_set))
439 break;
440 read (error_pipe[0], error + len, 1);
441 len ++;
442 }
443 error[len] = 0;
444 close (error_pipe[0]);
445 }
446 if (len > 0)
447 message (0, _(" Warning "), error);
448 }
449
450 static struct sigaction ignore, save_intr, save_quit, save_stop;
451
452 /* INHANDLE is a result of some mc_open call to any vfs, this function
453 returns a normal handle (to be used with read) of a pipe for reading
454 of the output of COMMAND with arguments ... (must include argv[0] as
455 well) which gets as its input at most INLEN bytes from the INHANDLE
456 using mc_read. You have to call mc_doublepclose to close the returned
457 handle afterwards. If INLEN is -1, we read as much as we can :) */
458 int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
459 {
460 int pipe0 [2], pipe1 [2];
461 pid_t pid;
462
463 #define closepipes() close(pipe0[0]);close(pipe0[1]);close(pipe1[0]);close(pipe1[1])
464 #define is_a_pipe_fd(f) ((pipe0[0] == f) || (pipe0[1] == f) || (pipe1[0] == f) || (pipe1[1] == f))
465
466 pipe (pipe0); pipe (pipe1);
467 ignore.sa_handler = SIG_IGN;
468 sigemptyset (&ignore.sa_mask);
469 ignore.sa_flags = 0;
470
471 sigaction (SIGINT, &ignore, &save_intr);
472 sigaction (SIGQUIT, &ignore, &save_quit);
473 sigaction (SIGTSTP, &startup_handler, &save_stop);
474
475 switch (pid = fork ()) {
476 case -1:
477 closepipes ();
478 return -1;
479 case 0: {
480 sigaction (SIGINT, &save_intr, NULL);
481 sigaction (SIGQUIT, &save_quit, NULL);
482
483 switch (pid = fork ()) {
484 case -1:
485 closepipes ();
486 exit (1);
487 case 0: {
488 #define MAXARGS 16
489 int argno;
490 char *args[MAXARGS];
491 va_list ap;
492 int nulldevice;
493
494 port_shutdown_extra_fds ();
495
496 nulldevice = open ("/dev/null", O_WRONLY);
497 close (0);
498 dup (pipe0 [0]);
499 close (1);
500 dup (pipe1 [1]);
501 close (2);
502 dup (nulldevice);
503 close (nulldevice);
504 closepipes ();
505 va_start (ap, command);
506 argno = 0;
507 while ((args[argno++] = va_arg(ap, char *)) != NULL)
508 if (argno == (MAXARGS - 1)) {
509 args[argno] = NULL;
510 break;
511 }
512 va_end (ap);
513 execvp (command, args);
514 exit (0);
515 }
516 default:
517 {
518 char buffer [8192];
519 int i;
520
521 close (pipe0 [0]);
522 close (pipe1 [0]);
523 close (pipe1 [1]);
524 while ((i = mc_read (inhandle, buffer,
525 (inlen == -1 || inlen > 8192)
526 ? 8192 : inlen)) > 0) {
527 write (pipe0 [1], buffer, i);
528 if (inlen != -1) {
529 inlen -= i;
530 if (!inlen)
531 break;
532 }
533 }
534 close (pipe0 [1]);
535 while (waitpid (pid, &i, 0) < 0)
536 if (errno != EINTR)
537 break;
538
539 port_shutdown_extra_fds ();
540 exit (i);
541 }
542 }
543 }
544 default:
545 *the_pid = pid;
546 break;
547 }
548 close (pipe0 [0]);
549 close (pipe0 [1]);
550 close (pipe1 [1]);
551 return pipe1 [0];
552 }
553
554 int mc_doublepclose (int pipe, pid_t pid)
555 {
556 int status = 0;
557
558 close (pipe);
559 waitpid (pid, &status, 0);
560 #ifdef SCO_FLAVOR
561 waitpid (-1, NULL, WNOHANG);
562 #endif /* SCO_FLAVOR */
563 sigaction (SIGINT, &save_intr, NULL);
564 sigaction (SIGQUIT, &save_quit, NULL);
565 sigaction (SIGTSTP, &save_stop, NULL);
566
567 return status;
568 }
569
570 /* Canonicalize path, and return a new path. Do everything in situ.
571 The new path differs from path in:
572 Multiple `/'s are collapsed to a single `/'.
573 Leading `./'s and trailing `/.'s are removed.
574 Trailing `/'s are removed.
575 Non-leading `../'s and trailing `..'s are handled by removing
576 portions of the path. */
577 char *canonicalize_pathname (char *path)
578 {
579 int i, start;
580 char stub_char;
581
582 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
583
584 /* Walk along path looking for things to compact. */
585 i = 0;
586 for (;;) {
587 if (!path[i])
588 break;
589
590 while (path[i] && path[i] != PATH_SEP)
591 i++;
592
593 start = i++;
594
595 /* If we didn't find any slashes, then there is nothing left to do. */
596 if (!path[start])
597 break;
598
599 #if defined(__QNX__)
600 /*
601 ** QNX accesses the directories of nodes on its peer-to-peer
602 ** network by prefixing their directories with "//[nid]".
603 ** We don't want to collapse two '/'s if they're at the start
604 ** of the path, followed by digits, and ending with a '/'.
605 */
606 if (start == 0 && i == 1)
607 {
608 char *p = path + 2;
609 char *q = strchr(p, PATH_SEP);
610
611 if (q > p)
612 {
613 *q = 0;
614 if (!strcspn(p, "0123456789"))
615 {
616 start = q - path;
617 i = start + 1;
618 }
619 *q = PATH_SEP;
620 }
621 }
622 #endif
623
624 /* Handle multiple `/'s in a row. */
625 while (path[i] == PATH_SEP)
626 i++;
627
628 if ((start + 1) != i) {
629 strcpy (path + start + 1, path + i);
630 i = start + 1;
631 }
632
633 /* Handle backquoted `/'. */
634 if (start > 0 && path[start - 1] == '\\')
635 continue;
636
637 /* Check for trailing `/'. */
638 if (start && !path[i]) {
639 zero_last:
640 path[--i] = '\0';
641 break;
642 }
643
644 /* Check for `../', `./' or trailing `.' by itself. */
645 if (path[i] == '.') {
646 /* Handle trailing `.' by itself. */
647 if (!path[i + 1])
648 goto zero_last;
649
650 /* Handle `./'. */
651 if (path[i + 1] == PATH_SEP) {
652 strcpy (path + i, path + i + 1);
653 i = start;
654 continue;
655 }
656
657 /* Handle `../' or trailing `..' by itself.
658 Remove the previous ?/ part with the exception of
659 ../, which we should leave intact. */
660 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
661 while (--start > -1 && path[start] != PATH_SEP);
662 if (!strncmp (path + start + 1, "../", 3))
663 continue;
664 strcpy (path + start + 1, path + i + 2);
665 i = start;
666 continue;
667 }
668 }
669 }
670
671 if (!*path) {
672 *path = stub_char;
673 path[1] = '\0';
674 }
675 return path;
676 }
677
678 #ifdef SCO_FLAVOR
679 int gettimeofday( struct timeval * tv, struct timezone * tz)
680 {
681 struct timeb tb;
682 struct tm * l;
683
684 ftime( &tb );
685 if (errno == EFAULT)
686 return -1;
687 l = localtime(&tb.time);
688 tv->tv_sec = l->tm_sec;
689 tv->tv_usec = (long) tb.millitm;
690 return 0;
691 }
692 #endif /* SCO_FLAVOR */
693
694 #ifndef HAVE_PUTENV
695
696 /* The following piece of code was copied from the GNU C Library */
697 /* And is provided here for nextstep who lacks putenv */
698
699 extern char **environ;
700
701 #ifndef HAVE_GNU_LD
702 #define __environ environ
703 #endif
704
705
706 /* Put STRING, which is of the form "NAME=VALUE", in the environment. */
707 int
708 putenv (const char *string)
709 {
710 const char *const name_end = strchr (string, '=');
711 register size_t size;
712 register char **ep;
713
714 if (name_end == NULL){
715 /* Remove the variable from the environment. */
716 size = strlen (string);
717 for (ep = __environ; *ep != NULL; ++ep)
718 if (!strncmp (*ep, string, size) && (*ep)[size] == '='){
719 while (ep[1] != NULL){
720 ep[0] = ep[1];
721 ++ep;
722 }
723 *ep = NULL;
724 return 0;
725 }
726 }
727
728 size = 0;
729 for (ep = __environ; *ep != NULL; ++ep)
730 if (!strncmp (*ep, string, name_end - string) &&
731 (*ep)[name_end - string] == '=')
732 break;
733 else
734 ++size;
735
736 if (*ep == NULL){
737 static char **last_environ = NULL;
738 char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
739 if (new_environ == NULL)
740 return -1;
741 (void) memcpy ((void *) new_environ, (void *) __environ,
742 size * sizeof (char *));
743 new_environ[size] = (char *) string;
744 new_environ[size + 1] = NULL;
745 if (last_environ != NULL)
746 free ((void *) last_environ);
747 last_environ = new_environ;
748 __environ = new_environ;
749 }
750 else
751 *ep = (char *) string;
752
753 return 0;
754 }
755 #endif /* !HAVE_PUTENV */
756
757 void my_statfs (struct my_statfs *myfs_stats, char *path)
758 {
759 int i, len = 0;
760
761 #ifndef NO_INFOMOUNT
762 struct mount_entry *entry = NULL;
763 struct mount_entry *temp = mount_list;
764 struct fs_usage fs_use;
765
766 while (temp){
767 i = strlen (temp->me_mountdir);
768 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
769 if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
770 len = i;
771 entry = temp;
772 }
773 temp = temp->me_next;
774 }
775
776 if (entry){
777 get_fs_usage (entry->me_mountdir, &fs_use);
778
779 myfs_stats->type = entry->me_dev;
780 myfs_stats->typename = entry->me_type;
781 myfs_stats->mpoint = entry->me_mountdir;
782 myfs_stats->device = entry->me_devname;
783 myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
784 myfs_stats->total = fs_use.fsu_blocks/2;
785 myfs_stats->nfree = fs_use.fsu_ffree;
786 myfs_stats->nodes = fs_use.fsu_files;
787 } else
788 #endif
789 #if defined(NO_INFOMOUNT) && defined(__QNX__)
790 /*
791 ** This is the "other side" of the hack to read_filesystem_list() in
792 ** mountlist.c.
793 ** It's not the most efficient approach, but consumes less memory. It
794 ** also accomodates QNX's ability to mount filesystems on the fly.
795 */
796 struct mount_entry *entry;
797 struct fs_usage fs_use;
798
799 if ((entry = read_filesystem_list(0, 0)) != NULL)
800 {
801 get_fs_usage(entry->me_mountdir, &fs_use);
802
803 myfs_stats->type = entry->me_dev;
804 myfs_stats->typename = entry->me_type;
805 myfs_stats->mpoint = entry->me_mountdir;
806 myfs_stats->device = entry->me_devname;
807
808 myfs_stats->avail = fs_use.fsu_bfree / 2;
809 myfs_stats->total = fs_use.fsu_blocks / 2;
810 myfs_stats->nfree = fs_use.fsu_ffree;
811 myfs_stats->nodes = fs_use.fsu_files;
812 }
813 else
814 #endif
815 {
816 myfs_stats->type = 0;
817 myfs_stats->mpoint = "unknown";
818 myfs_stats->device = "unknown";
819 myfs_stats->avail = 0;
820 myfs_stats->total = 0;
821 myfs_stats->nfree = 0;
822 myfs_stats->nodes = 0;
823 }
824 }
825
826 #ifdef HAVE_GET_PROCESS_STATS
827 # include <sys/procstats.h>
828
829 int gettimeofday (struct timeval *tp, void *tzp)
830 {
831 return get_process_stats(tp, PS_SELF, 0, 0);
832 }
833 #endif
834
835 #ifdef SCO_FLAVOR
836 /* Define this only for SCO */
837 #ifdef USE_NETCODE
838 #ifndef HAVE_SOCKETPAIR
839
840 /*
841 The code for s_pipe function is adapted from Section 7.9
842 of the "UNIX Network Programming" by W. Richard Stevens,
843 published by Prentice Hall, ISBN 0-13-949876-1
844 (c) 1990 by P T R Prentice Hall
845
846 It is used to implement socketpair function for SVR3 systems
847 that lack it.
848 */
849
850 #include <sys/types.h>
851 #include <sys/stream.h> /* defines queue_t */
852 #include <stropts.h> /* defines struct strtdinsert */
853 #include <fcntl.h>
854
855 #define SPX_DEVICE "/dev/spx"
856 #define S_PIPE_HANDLE_ERRNO 1
857 /* if the above is defined to 1, we will attempt to
858 save and restore errno to indicate failure
859 reason to the caller;
860 Please note that this will not work in environments
861 where errno is not just an integer
862 */
863
864 #if S_PIPE_HANDLE_ERRNO
865 #include <errno.h>
866 /* This is for "extern int errno;" */
867 #endif
868
869 /* s_pipe returns 0 if OK, -1 on error */
870 /* two file descriptors are returned */
871 int s_pipe(int fd[2])
872 {
873 struct strfdinsert ins; /* stream I_FDINSERT ioctl format */
874 queue_t *pointer;
875 #if S_PIPE_HANDLE_ERRNO
876 int err_save;
877 #endif
878 /*
879 * First open the stream clone device "dev/spx" twice,
880 * obtaining the two file descriptors
881 */
882
883 if ( (fd[0] = open(SPX_DEVICE, O_RDWR)) < 0)
884 return -1;
885 if ( (fd[1] = open(SPX_DEVICE, O_RDWR)) < 0) {
886 #if S_PIPE_HANDLE_ERRNO
887 err_save = errno;
888 #endif
889 close(fd[0]);
890 #if S_PIPE_HANDLE_ERRNO
891 errno = err_save;
892 #endif
893 return -1;
894 }
895
896 /*
897 * Now link these two stream together with an I_FDINSERT ioctl.
898 */
899
900 ins.ctlbuf.buf = (char *) &pointer; /* no control information, just the pointer */
901 ins.ctlbuf.maxlen = sizeof pointer;
902 ins.ctlbuf.len = sizeof pointer;
903 ins.databuf.buf = (char *) 0; /* no data to be sent */
904 ins.databuf.maxlen = 0;
905 ins.databuf.len = -1; /* magic: must be -1 rather than 0 for stream pipes */
906
907 ins.fildes = fd[1]; /* the fd to connect with fd[0] */
908 ins.flags = 0; /* nonpriority message */
909 ins.offset = 0; /* offset of pointer in control buffer */
910
911 if (ioctl(fd[0], I_FDINSERT, (char *) &ins) < 0) {
912 #if S_PIPE_HANDLE_ERRNO
913 err_save = errno;
914 #endif
915 close(fd[0]);
916 close(fd[1]);
917 #if S_PIPE_HANDLE_ERRNO
918 errno = err_save;
919 #endif
920 return -1;
921 }
922 /* all is OK if we came here, indicate success */
923 return 0;
924 }
925
926 int socketpair(int dummy1, int dummy2, int dummy3, int fd[2])
927 {
928 return s_pipe(fd);
929 }
930
931 #endif /* ifndef HAVE_SOCKETPAIR */
932 #endif /* ifdef USE_NETCODE */
933 #endif /* SCO_FLAVOR */