Codepage messages related translated & other stuff...
[midnight-commander.git] / src / utilunix.c
blob4a729ece4304b9642827cf25e18bf4ed1c551ed8
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.
7 The file_date routine is mostly from GNU's fileutils package,
8 written by Richard Stallman and David MacKenzie.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include <config.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <fcntl.h>
31 #include <signal.h> /* my_system */
32 #include <limits.h> /* INT_MAX */
33 #include <sys/time.h> /* select: timeout */
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <stdarg.h>
38 #ifdef HAVE_SYS_WAIT_H
39 # include <sys/wait.h> /* my_system */
40 #endif
41 #include <errno.h> /* my_system */
42 #include <pwd.h>
43 #include <grp.h>
44 #include <string.h>
45 #include <ctype.h>
46 #ifdef HAVE_SYS_SELECT_H
47 # include <sys/select.h>
48 #endif
49 #ifdef SCO_FLAVOR
50 # include <sys/timeb.h>
51 #endif
52 #include <time.h>
53 #ifdef __linux__
54 # if defined(__GLIBC__) && (__GLIBC__ < 2)
55 # include <linux/termios.h> /* This is needed for TIOCLINUX */
56 # else
57 # include <termios.h>
58 # endif
59 # include <sys/ioctl.h>
60 #endif
61 #ifdef __QNX__
62 # include <unix.h> /* exec*() from <process.h> */
63 #endif
64 #include "global.h"
65 #include "fsusage.h"
66 #include "mountlist.h"
67 #include "dialog.h" /* message() */
68 #include "../vfs/vfs.h" /* mc_read() */
69 #include "x.h"
71 struct sigaction startup_handler;
72 extern struct mount_entry *mount_list;
74 uid_t current_user_uid;
75 user_in_groups *current_user_gid;
77 int
78 max_open_files (void)
80 static int files;
82 if (files)
83 return files;
85 #ifdef HAVE_SYSCONF
86 files = sysconf (_SC_OPEN_MAX);
87 if (files != -1)
88 return files;
89 #endif
90 #ifdef OPEN_MAX
91 return files = OPEN_MAX;
92 #else
93 return files = 256;
94 #endif
97 #ifndef VFS_STANDALONE
98 void init_groups (void)
100 int i;
101 struct passwd *pwd;
102 struct group *grp;
103 user_in_groups *cug, *pug;
105 pwd = getpwuid (current_user_uid=getuid ());
107 current_user_gid = (pug = g_new (user_in_groups, 1));
108 current_user_gid->gid = getgid ();
109 current_user_gid->next = NULL;
111 if (pwd == NULL)
112 return;
114 setgrent ();
115 while ((grp = getgrent ()))
116 for (i = 0; grp->gr_mem[i]; i++)
117 if (!strcmp (pwd->pw_name,grp->gr_mem[i]))
119 cug = g_new (user_in_groups, 1);
120 cug->gid = grp->gr_gid;
121 pug->next = cug;
122 cug->next = NULL;
123 pug = cug;
124 break;
126 endgrent ();
129 /* Return the index of permission triplet */
131 get_user_rights (struct stat *buf)
133 user_in_groups *cug;
135 if (buf->st_uid == current_user_uid || current_user_uid == 0)
136 return 0;
138 for (cug = current_user_gid; cug; cug = cug->next)
139 if (cug->gid == buf->st_gid) return 1;
141 return 2;
145 void
146 delete_groups (void)
148 user_in_groups *pug, *cug = current_user_gid;
150 while (cug){
151 pug = cug->next;
152 g_free (cug);
153 cug = pug;
157 #define UID_CACHE_SIZE 200
158 #define GID_CACHE_SIZE 30
160 typedef struct {
161 int index;
162 char *string;
163 } int_cache;
165 int_cache uid_cache [UID_CACHE_SIZE];
166 int_cache gid_cache [GID_CACHE_SIZE];
168 void init_uid_gid_cache (void)
170 int i;
172 for (i = 0; i < UID_CACHE_SIZE; i++)
173 uid_cache [i].string = 0;
175 for (i = 0; i < GID_CACHE_SIZE; i++)
176 gid_cache [i].string = 0;
179 static char *i_cache_match (int id, int_cache *cache, int size)
181 int i;
183 for (i = 0; i < size; i++)
184 if (cache [i].index == id)
185 return cache [i].string;
186 return 0;
189 static void i_cache_add (int id, int_cache *cache, int size, char *text,
190 int *last)
192 if (cache [*last].string)
193 g_free (cache [*last].string);
194 cache [*last].string = g_strdup (text);
195 cache [*last].index = id;
196 *last = ((*last)+1) % size;
199 char *get_owner (int uid)
201 struct passwd *pwd;
202 static char ibuf [10];
203 char *name;
204 static int uid_last;
206 if ((name = i_cache_match (uid, uid_cache, UID_CACHE_SIZE)) != NULL)
207 return name;
209 pwd = getpwuid (uid);
210 if (pwd){
211 i_cache_add (uid, uid_cache, UID_CACHE_SIZE, pwd->pw_name, &uid_last);
212 return pwd->pw_name;
214 else {
215 g_snprintf (ibuf, sizeof (ibuf), "%d", uid);
216 return ibuf;
220 char *get_group (int gid)
222 struct group *grp;
223 static char gbuf [10];
224 char *name;
225 static int gid_last;
227 if ((name = i_cache_match (gid, gid_cache, GID_CACHE_SIZE)) != NULL)
228 return name;
230 grp = getgrgid (gid);
231 if (grp){
232 i_cache_add (gid, gid_cache, GID_CACHE_SIZE, grp->gr_name, &gid_last);
233 return grp->gr_name;
234 } else {
235 g_snprintf (gbuf, sizeof (gbuf), "%d", gid);
236 return gbuf;
240 /* Since ncurses uses a handler that automatically refreshes the */
241 /* screen after a SIGCONT, and we don't want this behavior when */
242 /* spawning a child, we save the original handler here */
243 void save_stop_handler (void)
245 sigaction (SIGTSTP, NULL, &startup_handler);
247 #endif /* VFS_STANDALONE */
249 #ifdef HAVE_GNOME
250 #define PORT_HAS_MY_SYSTEM 1
251 #endif
253 #ifndef PORT_HAS_MY_SYSTEM
254 int my_system (int flags, const char *shell, const char *command)
256 struct sigaction ignore, save_intr, save_quit, save_stop;
257 pid_t pid;
258 int status = 0;
260 ignore.sa_handler = SIG_IGN;
261 sigemptyset (&ignore.sa_mask);
262 ignore.sa_flags = 0;
264 sigaction (SIGINT, &ignore, &save_intr);
265 sigaction (SIGQUIT, &ignore, &save_quit);
267 /* Restore the original SIGTSTP handler, we don't want ncurses' */
268 /* handler messing the screen after the SIGCONT */
269 sigaction (SIGTSTP, &startup_handler, &save_stop);
271 if ((pid = fork ()) < 0){
272 fprintf (stderr, "\n\nfork () = -1\n");
273 return -1;
275 if (pid == 0){
276 signal (SIGINT, SIG_DFL);
277 signal (SIGQUIT, SIG_DFL);
278 signal (SIGTSTP, SIG_DFL);
279 signal (SIGCHLD, SIG_DFL);
281 #if 0
282 prepare_environment ();
283 #endif
285 #ifdef USE_VFS
286 if (flags & EXECUTE_SETUID)
287 # if defined (HAVE_SETUID)
288 setuid (vfs_uid);
289 # elif defined (HAVE_SETREUID)
290 setreuid (vfs_uid, vfs_uid);
291 # else
292 ; /* Can't drop privileges */
293 # endif
294 #endif
296 if (flags & EXECUTE_AS_SHELL)
297 execl (shell, shell, "-c", command, NULL);
298 else
299 execlp (shell, shell, command, NULL);
301 _exit (127); /* Exec error */
302 } else {
303 while (waitpid (pid, &status, 0) < 0)
304 if (errno != EINTR){
305 status = -1;
306 break;
309 sigaction (SIGINT, &save_intr, NULL);
310 sigaction (SIGQUIT, &save_quit, NULL);
311 sigaction (SIGTSTP, &save_stop, NULL);
313 #ifdef SCO_FLAVOR
314 waitpid(-1, NULL, WNOHANG);
315 #endif /* SCO_FLAVOR */
317 return WEXITSTATUS(status);
319 #endif
321 /* Returns a newly allocated string, if directory does not exist, return 0 */
322 char *tilde_expand (const char *directory)
324 struct passwd *passwd;
325 const char *p;
326 char *name;
328 if (*directory != '~')
329 return g_strdup (directory);
331 directory++;
333 p = strchr (directory, PATH_SEP);
335 /* d = "~" or d = "~/" */
336 if (!(*directory) || (*directory == PATH_SEP)){
337 passwd = getpwuid (geteuid ());
338 p = (*directory == PATH_SEP) ? directory+1 : "";
339 } else {
340 if (!p){
341 passwd = getpwnam (directory);
342 } else {
343 name = g_malloc (p - directory + 1);
344 strncpy (name, directory, p - directory);
345 name [p - directory] = 0;
346 passwd = getpwnam (name);
347 g_free (name);
351 /* If we can't figure the user name, return NULL */
352 if (!passwd)
353 return 0;
355 return g_strconcat (passwd->pw_dir, PATH_SEP_STR, p, NULL);
358 #ifndef VFS_STANDALONE
360 set_nonblocking (int fd)
362 int val;
364 val = fcntl (fd, F_GETFL, 0);
365 val |= O_NONBLOCK;
366 return fcntl (fd, F_SETFL, val) != -1;
369 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
370 /* More than that would be unportable */
371 #define MAX_PIPE_SIZE 4096
373 static int error_pipe[2]; /* File descriptors of error pipe */
374 static int old_error; /* File descriptor of old standard error */
376 /* Creates a pipe to hold standard error for a later analysis. */
377 /* The pipe can hold 4096 bytes. Make sure no more is written */
378 /* or a deadlock might occur. */
379 void open_error_pipe (void)
381 if (pipe (error_pipe) < 0){
382 message (0, _(" Warning "), _(" Pipe failed "));
384 old_error = dup (2);
385 if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
386 message (0, _(" Warning "), _(" Dup failed "));
387 close (error_pipe[0]);
388 close (error_pipe[1]);
390 close (error_pipe[1]);
394 * Returns true if an error was displayed
397 close_error_pipe (int error, char *text)
399 char *title;
400 char msg[MAX_PIPE_SIZE];
401 int len = 0;
403 if (error)
404 title = MSG_ERROR;
405 else
406 title = _(" Warning ");
407 if (old_error >= 0){
408 close (2);
409 dup (old_error);
410 close (old_error);
411 len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
413 if (len >= 0)
414 msg[len] = 0;
415 close (error_pipe[0]);
417 if (error < 0)
418 return 0; /* Just ignore error message */
419 if (text == NULL){
420 if (len == 0) return 0; /* Nothing to show */
422 /* Show message from pipe */
423 message (error, title, msg);
424 } else {
425 /* Show given text and possible message from pipe */
426 message (error, title, " %s \n %s ", text, msg);
428 return 1;
431 /* Checks for messages in the error pipe,
432 * closes the pipe and displays an error box if needed
434 void check_error_pipe (void)
436 char error[MAX_PIPE_SIZE];
437 int len = 0;
438 if (old_error >= 0){
439 while (len < MAX_PIPE_SIZE)
441 fd_set select_set;
442 struct timeval timeout;
443 FD_ZERO (&select_set);
444 FD_SET (error_pipe[0], &select_set);
445 timeout.tv_sec = 0;
446 timeout.tv_usec = 0;
447 select (FD_SETSIZE, &select_set, 0, 0, &timeout);
448 if (!FD_ISSET (0, &select_set))
449 break;
450 read (error_pipe[0], error + len, 1);
451 len ++;
453 error[len] = 0;
454 close (error_pipe[0]);
456 if (len > 0)
457 message (0, _(" Warning "), error);
459 #endif
461 static struct sigaction ignore, save_intr, save_quit, save_stop;
463 /* INHANDLE is a result of some mc_open call to any vfs, this function
464 returns a normal handle (to be used with read) of a pipe for reading
465 of the output of COMMAND with arguments ... (must include argv[0] as
466 well) which gets as its input at most INLEN bytes from the INHANDLE
467 using mc_read. You have to call mc_doublepclose to close the returned
468 handle afterwards. If INLEN is -1, we read as much as we can :) */
469 int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
471 int pipe0 [2], pipe1 [2];
472 pid_t pid;
474 #define closepipes() close(pipe0[0]);close(pipe0[1]);close(pipe1[0]);close(pipe1[1])
475 #define is_a_pipe_fd(f) ((pipe0[0] == f) || (pipe0[1] == f) || (pipe1[0] == f) || (pipe1[1] == f))
477 pipe (pipe0); pipe (pipe1);
478 ignore.sa_handler = SIG_IGN;
479 sigemptyset (&ignore.sa_mask);
480 ignore.sa_flags = 0;
482 sigaction (SIGINT, &ignore, &save_intr);
483 sigaction (SIGQUIT, &ignore, &save_quit);
484 sigaction (SIGTSTP, &startup_handler, &save_stop);
486 switch (pid = fork ()) {
487 case -1:
488 closepipes ();
489 return -1;
490 case 0: {
491 sigaction (SIGINT, &save_intr, NULL);
492 sigaction (SIGQUIT, &save_quit, NULL);
493 switch (pid = fork ()) {
494 case -1:
495 closepipes ();
496 exit (1);
497 case 0: {
498 #define MAXARGS 16
499 int argno;
500 char *args[MAXARGS];
501 va_list ap;
502 int nulldevice;
504 port_shutdown_extra_fds ();
506 nulldevice = open ("/dev/null", O_WRONLY);
507 close (0);
508 dup (pipe0 [0]);
509 close (1);
510 dup (pipe1 [1]);
511 close (2);
512 dup (nulldevice);
513 close (nulldevice);
514 closepipes ();
515 va_start (ap, command);
516 argno = 0;
517 while ((args[argno++] = va_arg(ap, char *)) != NULL)
518 if (argno == (MAXARGS - 1)) {
519 args[argno] = NULL;
520 break;
522 va_end (ap);
523 execvp (command, args);
524 exit (0);
526 default:
528 char buffer [8192];
529 int i;
531 close (pipe0 [0]);
532 close (pipe1 [0]);
533 close (pipe1 [1]);
534 while ((i = mc_read (inhandle, buffer,
535 (inlen == -1 || inlen > 8192)
536 ? 8192 : inlen)) > 0) {
537 write (pipe0 [1], buffer, i);
538 if (inlen != -1) {
539 inlen -= i;
540 if (!inlen)
541 break;
544 close (pipe0 [1]);
545 while (waitpid (pid, &i, 0) < 0)
546 if (errno != EINTR)
547 break;
549 port_shutdown_extra_fds ();
550 exit (i);
554 default:
555 *the_pid = pid;
556 break;
558 close (pipe0 [0]);
559 close (pipe0 [1]);
560 close (pipe1 [1]);
561 return pipe1 [0];
564 int mc_doublepclose (int pipe, pid_t pid)
566 int status = 0;
568 close (pipe);
569 waitpid (pid, &status, 0);
570 #ifdef SCO_FLAVOR
571 waitpid (-1, NULL, WNOHANG);
572 #endif /* SCO_FLAVOR */
573 sigaction (SIGINT, &save_intr, NULL);
574 sigaction (SIGQUIT, &save_quit, NULL);
575 sigaction (SIGTSTP, &save_stop, NULL);
577 return status;
580 /* Canonicalize path, and return a new path. Do everything in situ.
581 The new path differs from path in:
582 Multiple `/'s are collapsed to a single `/'.
583 Leading `./'s and trailing `/.'s are removed.
584 Trailing `/'s are removed.
585 Non-leading `../'s and trailing `..'s are handled by removing
586 portions of the path. */
587 char *canonicalize_pathname (char *path)
589 int i, start;
590 char stub_char;
592 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
594 /* Walk along path looking for things to compact. */
595 i = 0;
596 while (path[i]) {
598 while (path[i] && path[i] != PATH_SEP)
599 i++;
601 start = i++;
603 /* If we didn't find any slashes, then there is nothing left to do. */
604 if (!path[start])
605 break;
607 #if defined(__QNX__)
609 ** QNX accesses the directories of nodes on its peer-to-peer
610 ** network by prefixing their directories with "//[nid]".
611 ** We don't want to collapse two '/'s if they're at the start
612 ** of the path, followed by digits, and ending with a '/'.
614 if (start == 0 && i == 1)
616 char *p = path + 2;
617 char *q = strchr(p, PATH_SEP);
619 if (q > p)
621 *q = 0;
622 if (!strcspn(p, "0123456789"))
624 start = q - path;
625 i = start + 1;
627 *q = PATH_SEP;
630 #endif
632 /* Handle multiple `/'s in a row. */
633 while (path[i] == PATH_SEP)
634 i++;
636 if ((start + 1) != i) {
637 strcpy (path + start + 1, path + i);
638 i = start + 1;
641 /* Handle backquoted `/'. */
642 if (start > 0 && path[start - 1] == '\\')
643 continue;
645 /* Check for trailing `/'. */
646 if (start && !path[i]) {
647 zero_last:
648 path[--i] = '\0';
649 break;
652 /* Check for `../', `./' or trailing `.' by itself. */
653 if (path[i] == '.') {
654 /* Handle trailing `.' by itself. */
655 if (!path[i + 1])
656 goto zero_last;
658 /* Handle `./'. */
659 if (path[i + 1] == PATH_SEP) {
660 strcpy (path + i, path + i + 1);
661 i = start;
662 continue;
665 /* Handle `../' or trailing `..' by itself.
666 Remove the previous ?/ part with the exception of
667 ../, which we should leave intact. */
668 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
669 while (--start > -1 && path[start] != PATH_SEP);
670 if (!strncmp (path + start + 1, "../", 3))
671 continue;
672 strcpy (path + start + 1, path + i + 2);
673 i = start;
674 continue;
679 if (!*path) {
680 *path = stub_char;
681 path[1] = '\0';
683 return path;
686 #ifndef VFS_STANDALONE
687 #ifdef SCO_FLAVOR
688 int gettimeofday( struct timeval * tv, struct timezone * tz)
690 struct timeb tb;
691 struct tm * l;
693 ftime( &tb );
694 if (errno == EFAULT)
695 return -1;
696 l = localtime(&tb.time);
697 tv->tv_sec = l->tm_sec;
698 tv->tv_usec = (long) tb.millitm;
699 return 0;
701 #endif /* SCO_FLAVOR */
703 #ifndef HAVE_PUTENV
705 /* The following piece of code was copied from the GNU C Library */
706 /* And is provided here for nextstep who lacks putenv */
708 extern char **environ;
710 #ifndef HAVE_GNU_LD
711 #define __environ environ
712 #endif
715 /* Put STRING, which is of the form "NAME=VALUE", in the environment. */
717 putenv (const char *string)
719 const char *const name_end = strchr (string, '=');
720 register size_t size;
721 register char **ep;
723 if (name_end == NULL){
724 /* Remove the variable from the environment. */
725 size = strlen (string);
726 for (ep = __environ; *ep != NULL; ++ep)
727 if (!strncmp (*ep, string, size) && (*ep)[size] == '='){
728 while (ep[1] != NULL){
729 ep[0] = ep[1];
730 ++ep;
732 *ep = NULL;
733 return 0;
737 size = 0;
738 for (ep = __environ; *ep != NULL; ++ep)
739 if (!strncmp (*ep, string, name_end - string) &&
740 (*ep)[name_end - string] == '=')
741 break;
742 else
743 ++size;
745 if (*ep == NULL){
746 static char **last_environ = NULL;
747 char **new_environ = g_new (char *, size + 2);
748 if (new_environ == NULL)
749 return -1;
750 (void) memcpy ((void *) new_environ, (void *) __environ,
751 size * sizeof (char *));
752 new_environ[size] = (char *) string;
753 new_environ[size + 1] = NULL;
754 if (last_environ != NULL)
755 g_free ((void *) last_environ);
756 last_environ = new_environ;
757 __environ = new_environ;
759 else
760 *ep = (char *) string;
762 return 0;
764 #endif /* !HAVE_PUTENV */
766 void my_statfs (struct my_statfs *myfs_stats, char *path)
768 int i, len = 0;
770 #ifndef NO_INFOMOUNT
771 struct mount_entry *entry = NULL;
772 struct mount_entry *temp = mount_list;
773 struct fs_usage fs_use;
775 while (temp){
776 i = strlen (temp->me_mountdir);
777 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
778 if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
779 len = i;
780 entry = temp;
782 temp = temp->me_next;
785 if (entry){
786 get_fs_usage (entry->me_mountdir, &fs_use);
788 myfs_stats->type = entry->me_dev;
789 myfs_stats->typename = entry->me_type;
790 myfs_stats->mpoint = entry->me_mountdir;
791 myfs_stats->device = entry->me_devname;
792 myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
793 myfs_stats->total = fs_use.fsu_blocks/2;
794 myfs_stats->nfree = fs_use.fsu_ffree;
795 myfs_stats->nodes = fs_use.fsu_files;
796 } else
797 #endif
798 #if defined(NO_INFOMOUNT) && defined(__QNX__)
800 ** This is the "other side" of the hack to read_filesystem_list() in
801 ** mountlist.c.
802 ** It's not the most efficient approach, but consumes less memory. It
803 ** also accomodates QNX's ability to mount filesystems on the fly.
805 struct mount_entry *entry;
806 struct fs_usage fs_use;
808 if ((entry = read_filesystem_list(0, 0)) != NULL)
810 get_fs_usage(entry->me_mountdir, &fs_use);
812 myfs_stats->type = entry->me_dev;
813 myfs_stats->typename = entry->me_type;
814 myfs_stats->mpoint = entry->me_mountdir;
815 myfs_stats->device = entry->me_devname;
817 myfs_stats->avail = fs_use.fsu_bfree / 2;
818 myfs_stats->total = fs_use.fsu_blocks / 2;
819 myfs_stats->nfree = fs_use.fsu_ffree;
820 myfs_stats->nodes = fs_use.fsu_files;
822 else
823 #endif
825 myfs_stats->type = 0;
826 myfs_stats->mpoint = "unknown";
827 myfs_stats->device = "unknown";
828 myfs_stats->avail = 0;
829 myfs_stats->total = 0;
830 myfs_stats->nfree = 0;
831 myfs_stats->nodes = 0;
835 #ifdef HAVE_GET_PROCESS_STATS
836 # include <sys/procstats.h>
838 int gettimeofday (struct timeval *tp, void *tzp)
840 return get_process_stats(tp, PS_SELF, 0, 0);
842 #endif
844 #ifdef SCO_FLAVOR
845 /* Define this only for SCO */
846 #ifdef USE_NETCODE
847 #ifndef HAVE_SOCKETPAIR
850 The code for s_pipe function is adapted from Section 7.9
851 of the "UNIX Network Programming" by W. Richard Stevens,
852 published by Prentice Hall, ISBN 0-13-949876-1
853 (c) 1990 by P T R Prentice Hall
855 It is used to implement socketpair function for SVR3 systems
856 that lack it.
859 #include <sys/types.h>
860 #include <sys/stream.h> /* defines queue_t */
861 #include <stropts.h> /* defines struct strtdinsert */
862 #include <fcntl.h>
864 #define SPX_DEVICE "/dev/spx"
865 #define S_PIPE_HANDLE_ERRNO 1
866 /* if the above is defined to 1, we will attempt to
867 save and restore errno to indicate failure
868 reason to the caller;
869 Please note that this will not work in environments
870 where errno is not just an integer
873 #if S_PIPE_HANDLE_ERRNO
874 #include <errno.h>
875 /* This is for "extern int errno;" */
876 #endif
878 /* s_pipe returns 0 if OK, -1 on error */
879 /* two file descriptors are returned */
880 int s_pipe(int fd[2])
882 struct strfdinsert ins; /* stream I_FDINSERT ioctl format */
883 queue_t *pointer;
884 #if S_PIPE_HANDLE_ERRNO
885 int err_save;
886 #endif
888 * First open the stream clone device "dev/spx" twice,
889 * obtaining the two file descriptors
892 if ( (fd[0] = open(SPX_DEVICE, O_RDWR)) < 0)
893 return -1;
894 if ( (fd[1] = open(SPX_DEVICE, O_RDWR)) < 0) {
895 #if S_PIPE_HANDLE_ERRNO
896 err_save = errno;
897 #endif
898 close(fd[0]);
899 #if S_PIPE_HANDLE_ERRNO
900 errno = err_save;
901 #endif
902 return -1;
906 * Now link these two stream together with an I_FDINSERT ioctl.
909 ins.ctlbuf.buf = (char *) &pointer; /* no control information, just the pointer */
910 ins.ctlbuf.maxlen = sizeof pointer;
911 ins.ctlbuf.len = sizeof pointer;
912 ins.databuf.buf = (char *) 0; /* no data to be sent */
913 ins.databuf.maxlen = 0;
914 ins.databuf.len = -1; /* magic: must be -1 rather than 0 for stream pipes */
916 ins.fildes = fd[1]; /* the fd to connect with fd[0] */
917 ins.flags = 0; /* nonpriority message */
918 ins.offset = 0; /* offset of pointer in control buffer */
920 if (ioctl(fd[0], I_FDINSERT, (char *) &ins) < 0) {
921 #if S_PIPE_HANDLE_ERRNO
922 err_save = errno;
923 #endif
924 close(fd[0]);
925 close(fd[1]);
926 #if S_PIPE_HANDLE_ERRNO
927 errno = err_save;
928 #endif
929 return -1;
931 /* all is OK if we came here, indicate success */
932 return 0;
935 int socketpair(int dummy1, int dummy2, int dummy3, int fd[2])
937 return s_pipe(fd);
940 #endif /* ifndef HAVE_SOCKETPAIR */
941 #endif /* ifdef USE_NETCODE */
942 #endif /* SCO_FLAVOR */
943 #endif /* VFS_STANDALONE */
945 char *
946 g_readlink (char *path)
948 char small_buffer [80];
949 char *str;
950 int n, size;
952 n = readlink (path, small_buffer, sizeof (small_buffer)-1);
953 if (n == -1)
954 return NULL;
956 if (n < sizeof (small_buffer)-1){
957 small_buffer [n] = 0;
958 return g_strdup (small_buffer);
961 str = NULL;
962 for (size = 256; size < 8192; size += 128){
963 if (str)
964 g_free (str);
966 str = g_malloc (size);
968 n = readlink (path, str, size-1);
969 if (n == -1){
970 g_free (str);
971 return NULL;
974 if (n < size-1){
975 char *s;
977 str [n] = 0;
978 s = g_strdup (str);
979 g_free (str);
980 return s;
983 str [n] = 0;
984 return str;