1 /* $Header: /src/pub/tcsh/tc.os.c,v 3.53 2002/03/08 17:36:47 christos Exp $ */
3 * tc.os.c: OS Dependent builtin functions
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$Id: tc.os.c,v 3.53 2002/03/08 17:36:47 christos Exp $")
39 #include "ed.defns.h" /* for the function names */
43 #define TIOCGPGRP TIOCGETPGRP
44 #define TIOCSPGRP TIOCSETPGRP
52 /* dosetpath -- setpath built-in command
54 **********************************************************************
56 * 08-May-88 Richard Draves (rpd) at Carnegie-Mellon University
57 * Major changes to remove artificial limits on sizes and numbers
60 **********************************************************************
64 static Char STRCPATH
[] = {'C', 'P', 'A', 'T', 'H', '\0'};
65 static Char STRLPATH
[] = {'L', 'P', 'A', 'T', 'H', '\0'};
66 static Char STRMPATH
[] = {'M', 'P', 'A', 'T', 'H', '\0'};
68 static Char STREPATH
[] = {'E', 'P', 'A', 'T', 'H', '\0'};
71 static Char
*syspaths
[] = {STRKPATH
, STRCPATH
, STRLPATH
, STRMPATH
,
77 #define LOCALSYSPATH "/usr/local"
85 extern char *getenv();
87 Char
**pathvars
, **cmdargs
;
88 char **spaths
, **cpaths
, **cmds
;
90 unsigned int npaths
, ncmds
;
93 omask
= sigsetmask(sigmask(SIGINT
));
96 * setpath(3) uses stdio and we want 0, 1, 2 to work...
99 (void) dcopy(SHIN
, 0);
100 (void) dcopy(SHOUT
, 1);
101 (void) dcopy(SHDIAG
, 2);
105 for (i
= 1; arglist
[i
] && (arglist
[i
][0] != '-'); i
++);
108 cmdargs
= &arglist
[i
];
109 for (; arglist
[i
]; i
++);
110 ncmds
= i
- npaths
- 1;
114 pathvars
= &arglist
[1];
118 npaths
= (sizeof syspaths
/ sizeof *syspaths
) - 1;
122 /* note that npaths != 0 */
124 spaths
= (char **) xmalloc((size_t) npaths
* sizeof *spaths
);
125 setzero((char *) spaths
, npaths
* sizeof *spaths
);
126 cpaths
= (char **) xmalloc((size_t) (npaths
+ 1) * sizeof *cpaths
);
127 setzero((char *) cpaths
, (npaths
+ 1) * sizeof *cpaths
);
128 cmds
= (char **) xmalloc((size_t) (ncmds
+ 1) * sizeof *cmds
);
129 setzero((char *) cmds
, (ncmds
+ 1) * sizeof *cmds
);
130 for (i
= 0; i
< npaths
; i
++) {
131 char *val
= getenv(short2str(pathvars
[i
]));
136 spaths
[i
] = (char *) xmalloc((size_t) (Strlen(pathvars
[i
]) +
137 strlen(val
) + 2) * sizeof **spaths
);
138 (void) strcpy(spaths
[i
], short2str(pathvars
[i
]));
139 (void) strcat(spaths
[i
], "=");
140 (void) strcat(spaths
[i
], val
);
141 cpaths
[i
] = spaths
[i
];
144 for (i
= 0; i
< ncmds
; i
++) {
145 Char
*val
= globone(cmdargs
[i
], G_ERROR
);
149 cmds
[i
] = (char *) xmalloc((size_t) Strlen(val
) + 1);
150 (void) strcpy(cmds
[i
], short2str(val
));
154 if (setpath(cpaths
, cmds
, LOCALSYSPATH
, sysflag
, 1) < 0) {
157 for (i
= 0; i
< npaths
; i
++)
159 xfree((ptr_t
) spaths
[i
]);
160 xfree((ptr_t
) spaths
);
163 xfree((ptr_t
) cpaths
);
165 for (i
= 0; i
< ncmds
; i
++)
167 xfree((ptr_t
) cmds
[i
]);
171 (void) sigsetmask(omask
);
176 for (i
= 0; i
< npaths
; i
++) {
179 name
= str2short(cpaths
[i
]);
180 for (val
= str2short(cpaths
[i
]); val
&& *val
&& *val
!= '='; val
++);
181 if (val
&& *val
== '=') {
185 if (Strcmp(name
, STRKPATH
) == 0) {
193 (void) sigsetmask(omask
);
208 char xvers
[MAXPATHLEN
];
210 if (getxvers(xvers
, MAXPATHLEN
) == -1)
211 stderror(ERR_SYSTEM
, "getxvers", strerror(errno
));
212 xprintf("%s\n", xvers
);
225 if (!*v
|| *v
[0] == '\0')
228 xvers
= short2str(*v
);
229 if (setxvers(xvers
) == -1)
230 stderror(ERR_SYSTEM
, "setxvers", strerror(errno
));
235 # define XC_PDP11 0x01
238 # define XC_8086 0x04
242 # define XC_16032 0x08
245 # define XC_S370 0x0b
247 # include <sys/x.out.h>
250 static struct xc_cpu_t
{
255 { XC_PDP11
, "pdp11" },
259 { XC_68K
, "mc68000" },
262 { XC_16032
, "ns16032" },
265 { XC_S370
, "xa370" },
270 * our local hack table, stolen from x.out.h
278 for (i
= 0; xcpu
[i
].xc_name
!= NULL
; i
++)
279 if (xcpu
[i
].xc_id
== xcid
)
280 return (xcpu
[i
].xc_name
);
290 for (i
= 0; xcpu
[i
].xc_name
!= NULL
; i
++)
291 if (strcmp(xcpu
[i
].xc_name
, xcname
) == 0)
292 return (xcpu
[i
].xc_id
);
304 sitepath_t p
[MAXSITE
];
306 static char *local
= "LOCAL ";
308 if ((j
= getspath(p
, MAXSITE
)) == -1)
309 stderror(ERR_SYSTEM
, "getspath", strerror(errno
));
310 for (i
= 0; i
< j
&& (p
[i
] & SPATH_CPU
) != NOSITE
; i
++) {
311 if (p
[i
] & SPATH_CPU
) {
312 if ((p
[i
] & SPATH_MASK
) == NULLSITE
)
314 else if ((st
= sfxcode((short) (p
[i
] & SPATH_MASK
))) != NULL
)
315 xprintf("%s ", st
->sf_ctype
);
317 char *xc
= getxcode(p
[i
] & SPATH_MASK
);
322 xprintf("*cpu %d* ", (int) (p
[i
] & SPATH_MASK
));
324 * BUG in the aix code... needs that cause if
325 * sfxcode fails once it fails for ever
331 if (p
[i
] == NULLSITE
)
333 else if ((st
= sfnum(p
[i
])) != NULL
)
334 xprintf("%s ", st
->sf_sname
);
336 xprintf("*site %d* ", (int) (p
[i
] & SPATH_MASK
));
352 sitepath_t p
[MAXSITE
];
356 * sfname() on AIX G9.9 at least, mallocs too pointers p, q
357 * then does the equivalent of while (*p++ == *q++) continue;
358 * and then tries to free(p,q) them! Congrats to the wizard who
359 * wrote that one. I bet he tested it really well too.
360 * Sooo, we set dont_free :-)
363 for (i
= 0, v
++; *v
&& *v
[0] != '\0'; v
++, i
++) {
367 else if (strcmp(s
, "LOCAL") == 0)
369 else if ((st
= sfctype(s
)) != NULL
)
370 p
[i
] = SPATH_CPU
| st
->sf_ccode
;
371 else if ((j
= getxid(s
)) != -1)
372 p
[i
] = SPATH_CPU
| j
;
373 else if ((st
= sfname(s
)) != NULL
)
377 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 1, "Bad cpu/site name"));
379 if (i
== MAXSITE
- 1)
380 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 2, "Site path too long"));
382 if (setspath(p
, i
) == -1)
383 stderror(ERR_SYSTEM
, "setspath", strerror(errno
));
388 * Return the site name where the process is running
397 if ((ss
= site(pid
)) == -1 || (st
= sfnum(ss
)) == NULL
)
398 return CGETS(23, 3, "unknown");
404 migratepid(pid
, new_site
)
411 need_local
= (pid
== 0) || (pid
== getpid());
413 if (kill3((pid_t
) pid
, SIGMIGRATE
, new_site
) < 0) {
414 xprintf("%d: %s\n", pid
, strerror(errno
));
419 if ((new_site
= site(0)) == -1) {
420 xprintf(CGETS(23, 4, "site: %s\n"), strerror(errno
));
423 if ((st
= sfnum(new_site
)) == NULL
) {
424 xprintf(CGETS(23, 5, "%d: Site not found\n"), new_site
);
427 if (setlocal(st
->sf_local
, strlen(st
->sf_local
)) == -1) {
428 xprintf(CGETS(23, 6, "setlocal: %s: %s\n"),
429 st
->sf_local
, strerror(errno
));
448 siteno_t new_site
= 0;
452 omask
= sigmask(SIGCHLD
);
454 omask
|= sigmask(SIGINT
);
455 omask
= sigblock(omask
) & ~omask
;
458 (void) sighold(SIGINT
);
459 (void) sighold(SIGCHLD
);
467 s
= short2str(&v
[0][1]);
469 * see comment in setspath()
472 if ((st
= sfname(s
)) == NULL
) {
474 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 7, "Site not found"));
477 new_site
= st
->sf_id
;
481 if (!*v
|| *v
[0] == '\0') {
482 if (migratepid(0, new_site
) == -1)
490 stderror(ERR_NAME
| ERR_NOMATCH
);
493 v
= gargv
= saveblk(v
);
497 while (v
&& (cp
= *v
)) {
500 if (kill3((pid_t
) - pp
->p_jobid
, SIGMIGRATE
, new_site
) < 0) {
501 xprintf("%S: %s\n", cp
, strerror(errno
));
505 else if (!(Isdigit(*cp
) || *cp
== '-'))
506 stderror(ERR_NAME
| ERR_JOBARGS
);
508 pid
= atoi(short2str(cp
));
509 if (migratepid(pid
, new_site
) == -1)
515 blkfree(gargv
), gargv
= 0;
520 (void) sigsetmask(omask
);
522 (void) sigrelse(SIGCHLD
);
524 (void) sigrelse(SIGINT
);
527 stderror(ERR_SILENT
);
533 *** CRAY ddmode <velo@sesun3.epfl.ch> (Martin Ouwehand EPFL-SIC/SE)
535 #if defined(_CRAY) && !defined(_CRAYMPP)
550 xprintf("%d\n",mode
);
554 stderror(ERR_NAME
| ERR_STRING
,
555 CGETS(23, 30, "Too many arguments"));
565 stderror(ERR_NAME
| ERR_STRING
,
566 CGETS(23, 31, "Invalid argument"));
570 #endif /* _CRAY && !_CRAYMPP */
579 * handle the funky warping of symlinks
582 #include <sys/warp.h>
584 static jmp_buf sigsys_buf
;
589 longjmp(sigsys_buf
, 1);
601 void (*old_sigsys_handler
) () = 0;
604 if (setjmp(sigsys_buf
)) {
605 signal(SIGSYS
, old_sigsys_handler
);
606 stderror(ERR_NAME
| ERR_STRING
,
607 CGETS(23, 8, "You're trapped in a universe you never made"));
610 old_sigsys_handler
= signal(SIGSYS
, catch_sigsys
);
615 if (*v
== 0) { /* display warp value */
617 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 9, "Getwarp failed"));
618 we
= getwarpbyvalue(warp
);
620 printf("%s\n", we
->w_name
);
622 printf("%d\n", warp
);
624 else { /* set warp value */
626 newwarp
= short2str(*v
);
628 warp
= atoi(newwarp
);
630 we
= getwarpbyname(newwarp
);
636 if ((warp
< 0) || (warp
>= WARP_MAXLINK
))
637 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 10, "Invalid warp"));
638 if ((setwarp(warp
) < 0) || (getwarp() != warp
)) {
639 (void) setwarp(oldwarp
);
640 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 11, "Setwarp failed"));
643 signal(SIGSYS
, old_sigsys_handler
);
651 /* Added, DAS DEC-90. */
652 #if defined(masscomp) || defined(_CX_UX)
659 register Char
*cp
= v
[1];
660 register Char
*cp2
; /* dunno how many elements v comes in with */
663 register sigmask_t omask
= 0;
667 (void) getuniverse(ubuf
);
668 xprintf("%s\n", ubuf
);
673 if (*cp
== '\0' || setuniverse(short2str(cp
)) != 0)
674 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 12, "Illegal universe"));
677 (void) getuniverse(ubuf
);
678 if (*cp
== '\0' || setuniverse(short2str(cp
)) != 0)
679 stderror(ERR_NAME
| ERR_STRING
, CGETS(23, 12, "Illegal universe"));
682 omask
= sigblock(sigmask(SIGINT
)) & ~sigmask(SIGINT
);
684 (void) sighold(SIGINT
);
689 (void) sigsetmask(omask
);
691 (void) sigrelse (SIGINT
);
694 (void) setuniverse(ubuf
);
698 #endif /* masscomp || _CX_UX */
707 register Char
*cp
= v
[1];
710 register sigmask_t omask
= 0;
714 (void) setuniverse("att");
716 (void) getuniverse(ubuf
);
717 (void) setuniverse("att");
720 omask
= sigblock(sigmask(SIGINT
)) & ~sigmask(SIGINT
);
722 (void) sighold(SIGINT
);
727 (void) sigsetmask(omask
);
729 (void) sigrelse (SIGINT
);
732 (void) setuniverse(ubuf
);
742 register Char
*cp
= v
[1];
745 register sigmask_t omask
= 0;
749 (void) setuniverse("ucb");
751 (void) getuniverse(ubuf
);
752 (void) setuniverse("ucb");
755 omask
= sigblock(sigmask(SIGINT
)) & ~sigmask(SIGINT
);
757 (void) sighold(SIGINT
);
762 (void) sigsetmask(omask
);
764 (void) sigrelse (SIGINT
);
767 (void) setuniverse(ubuf
);
774 * Compute the difference in process stats.
777 pr_stat_sub(p2
, p1
, pr
)
778 struct process_stats
*p2
, *p1
, *pr
;
780 pr
->ps_utime
.tv_sec
= p2
->ps_utime
.tv_sec
- p1
->ps_utime
.tv_sec
;
781 pr
->ps_utime
.tv_usec
= p2
->ps_utime
.tv_usec
- p1
->ps_utime
.tv_usec
;
782 if (pr
->ps_utime
.tv_usec
< 0) {
783 pr
->ps_utime
.tv_sec
-= 1;
784 pr
->ps_utime
.tv_usec
+= 1000000;
786 pr
->ps_stime
.tv_sec
= p2
->ps_stime
.tv_sec
- p1
->ps_stime
.tv_sec
;
787 pr
->ps_stime
.tv_usec
= p2
->ps_stime
.tv_usec
- p1
->ps_stime
.tv_usec
;
788 if (pr
->ps_stime
.tv_usec
< 0) {
789 pr
->ps_stime
.tv_sec
-= 1;
790 pr
->ps_stime
.tv_usec
+= 1000000;
793 pr
->ps_maxrss
= p2
->ps_maxrss
- p1
->ps_maxrss
;
794 pr
->ps_pagein
= p2
->ps_pagein
- p1
->ps_pagein
;
795 pr
->ps_reclaim
= p2
->ps_reclaim
- p1
->ps_reclaim
;
796 pr
->ps_zerofill
= p2
->ps_zerofill
- p1
->ps_zerofill
;
797 pr
->ps_pffincr
= p2
->ps_pffincr
- p1
->ps_pffincr
;
798 pr
->ps_pffdecr
= p2
->ps_pffdecr
- p1
->ps_pffdecr
;
799 pr
->ps_swap
= p2
->ps_swap
- p1
->ps_swap
;
800 pr
->ps_syscall
= p2
->ps_syscall
- p1
->ps_syscall
;
801 pr
->ps_volcsw
= p2
->ps_volcsw
- p1
->ps_volcsw
;
802 pr
->ps_involcsw
= p2
->ps_involcsw
- p1
->ps_involcsw
;
803 pr
->ps_signal
= p2
->ps_signal
- p1
->ps_signal
;
804 pr
->ps_lread
= p2
->ps_lread
- p1
->ps_lread
;
805 pr
->ps_lwrite
= p2
->ps_lwrite
- p1
->ps_lwrite
;
806 pr
->ps_bread
= p2
->ps_bread
- p1
->ps_bread
;
807 pr
->ps_bwrite
= p2
->ps_bwrite
- p1
->ps_bwrite
;
808 pr
->ps_phread
= p2
->ps_phread
- p1
->ps_phread
;
809 pr
->ps_phwrite
= p2
->ps_phwrite
- p1
->ps_phwrite
;
812 #endif /* _SEQUENT_ */
816 /* This is a replacement for a missing memset function */
817 ptr_t
xmemset(loc
, value
, len
)
822 char *ptr
= (char *) loc
;
828 #endif /* NEEDmemset */
833 * This is the ANSI form of bcopy() with the arguments backwards...
834 * Unlike memcpy(), it handles overlaps between source and
838 xmemmove(vdst
, vsrc
, len
)
843 const char *src
= (const char *) vsrc
;
844 char *dst
= (char *) vdst
;
861 #endif /* NEEDmemmove */
872 /* ioctl will handle setting errno correctly. */
873 if (ioctl(fd
, TIOCGPGRP
, (ioctl_t
) & pgrp
) < 0)
879 * XXX: tcsetpgrp is not a macro any more cause on some systems,
880 * pid_t is a short, but the ioctl() takes a pointer to int (pyr)
881 * Thanks to Simon Day (simon@pharaoh.cyborg.bt.co.uk) for pointing
888 return ioctl(fd
, TIOCSPGRP
, (ioctl_t
) &pgrp
);
891 #endif /* tcgetpgrp */
892 #endif /* WINNT_NATIVE */
901 extern int yp_get_default_domain
__P((char **));
903 * PWP: The previous version assumed that yp domain was the same as the
904 * internet name domain. This isn't allways true. (Thanks to Mat Landau
905 * <mlandau@bbn.com> for the original version of this.)
907 if (yp_get_default_domain(&mydomain
) == 0) { /* if we got a name */
908 extern void yp_unbind
__P((const char *));
920 #if defined(NLS) && !defined(NOSTRCOLL)
922 * SunOS4 checks the file descriptor from openlocale() for <= 0
923 * instead of == -1. Someone should tell sun that file descriptor 0
924 * is valid! Our portable hack: open one so we call it with 0 used...
925 * We have to call this routine every time the locale changes...
927 * Of course it also tries to free the constant locale "C" it initially
928 * had allocated, with the sequence
932 * But we are smarter than that and just print a warning message.
935 static char *root
= "/";
938 fd
= open(root
, O_RDONLY
);
940 (void) strcoll(root
, root
);
946 #endif /* STRCOLLBUG */
958 setcompat(getcompat() & ~COMPAT_EXEC
);
959 sigignore(SIGIO
); /* ignore SIGIO */
964 struct sigstack inst
;
965 inst
.ss_sp
= (char *) xmalloc((size_t) 4192) + 4192;
967 sigstack(&inst
, NULL
);
977 * kill(SIGCONT) problems, don't know what this syscall does
978 * [schott@rzg.mpg.de]
980 syscall(151, getpid(), getpid());
989 static char errbuf
[128];
991 if (i
>= 0 && i
< sys_nerr
) {
992 return sys_errlist
[i
];
994 (void) xsnprintf(errbuf
, sizeof(errbuf
),
995 CGETS(23, 13, "Unknown Error: %d"), i
);
999 #endif /* strerror */
1002 # if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1003 # include <sys/utsname.h>
1004 # endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1007 xgethostname(name
, namlen
)
1011 # if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1015 retval
= uname(&uts
);
1018 xprintf(CGETS(23, 14, "sysname: %s\n"), uts
.sysname
);
1019 xprintf(CGETS(23, 15, "nodename: %s\n"), uts
.nodename
);
1020 xprintf(CGETS(23, 16, "release: %s\n"), uts
.release
);
1021 xprintf(CGETS(23, 17, "version: %s\n"), uts
.version
);
1022 xprintf(CGETS(23, 18, "machine: %s\n"), uts
.machine
);
1024 i
= strlen(uts
.nodename
) + 1;
1025 (void) strncpy(name
, uts
.nodename
, i
< namlen
? i
: namlen
);
1028 # else /* !_MINIX && !__EMX__ */
1031 (void) strncpy(name
, "OS/2", namlen
);
1033 (void) strncpy(name
, "minix", namlen
);
1034 # endif /* __EMX__ */
1035 name
[namlen
-1] = '\0';
1038 #endif /* _MINIX && !__EMX__ */
1039 } /* end xgethostname */
1040 #endif /* gethostname */
1043 # if defined(_MINIX) && defined(NICE)
1044 # undef _POSIX_SOURCE /* redefined in <lib.h> */
1045 # undef _MINIX /* redefined in <lib.h> */
1046 # undef HZ /* redefined in <minix/const.h> */
1048 # endif /* _MINIX && NICE */
1053 #if defined(_MINIX) && defined(NICE)
1054 return callm1(MM
, NICE
, incr
, 0, 0, NIL_PTR
, NIL_PTR
, NIL_PTR
);
1056 return /* incr ? 0 : */ 0;
1057 #endif /* _MINIX && NICE */
1062 static char *strnrcpy
__P((char *, char *, size_t));
1065 * Return the pathname of the current directory, or return
1066 * an error message in pathname.
1071 * From: Bernd Mohr <mohr@faui77.informatik.uni-erlangen.de>
1072 * I also ported the tcsh to the HP9000 Series 500. This computer
1073 * is a little bit different than the other HP 9000 computer. It has
1074 * a HP Chip instead of a Motorola CPU and it is no "real" UNIX. It runs
1075 * HP-UX which is emulated in top of a HP operating system. So, the last
1076 * supported version of HP-UX is 5.2 on the HP9000s500. This has two
1077 * consequences: it supports no job control and it has a filesystem
1078 * without "." and ".." !!!
1081 xgetcwd(pathname
, pathlen
)
1085 char pathbuf
[MAXNAMLEN
]; /* temporary pathname buffer */
1086 char *pnptr
= &pathbuf
[(sizeof pathbuf
)-1]; /* pathname pointer */
1087 dev_t rdev
; /* root device number */
1088 DIR *dirp
= NULL
; /* directory stream */
1089 ino_t rino
; /* root inode number */
1090 off_t rsize
; /* root size */
1091 struct direct
*dir
; /* directory entry struct */
1092 struct stat d
, dd
; /* file status struct */
1096 (void) stat("/.", &d
);
1101 if (stat(".", &d
) == -1) {
1102 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 24,
1103 "getcwd: Cannot stat \".\" (%s)"), strerror(errno
));
1106 if (d
.st_ino
== rino
&& d
.st_dev
== rdev
&& d
.st_size
== rsize
)
1107 break; /* reached root directory */
1108 if ((dirp
= opendir("..")) == NULL
) {
1109 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 19,
1110 "getcwd: Cannot open \"..\" (%s)"), strerror(errno
));
1113 if (chdir("..") == -1) {
1114 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 20,
1115 "getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno
));
1119 if ((dir
= readdir(dirp
)) == NULL
) {
1120 (void) xsnprintf(pathname
, pathlen
,
1121 CGETS(23, 21, "getcwd: Read error in \"..\" (%s)"),
1125 if (stat(dir
->d_name
, &dd
) == -1) {
1126 (void) xsnprintf(pathname
, pathlen
,
1127 CGETS(23, 25, "getcwd: Cannot stat directory \"%s\" (%s)"),
1128 dir
->d_name
, strerror(errno
));
1131 } while (dd
.st_ino
!= d
.st_ino
||
1132 dd
.st_dev
!= d
.st_dev
||
1133 dd
.st_size
!= d
.st_size
);
1134 (void) closedir(dirp
);
1136 pnptr
= strnrcpy(dirp
->d_name
, pnptr
, pnptr
- pathbuf
);
1137 pnptr
= strnrcpy("/", pnptr
, pnptr
- pathbuf
);
1140 if (*pnptr
== '\0') /* current dir == root dir */
1141 (void) strncpy(pathname
, "/", pathlen
);
1143 (void) strncpy(pathname
, pnptr
, pathlen
);
1144 pathname
[pathlen
- 1] = '\0';
1145 if (chdir(pnptr
) == -1) {
1146 (void) xsnprintf(pathname
, MAXPATHLEN
, CGETS(23, 22,
1147 "getcwd: Cannot change back to \".\" (%s)"),
1156 (void) chdir(strnrcpy(".", pnptr
, pnptr
- pathbuf
));
1161 # else /* ! hp9000s500 */
1163 # if (SYSVREL != 0 && !defined(d_fileno)) || defined(_VMS_POSIX) || defined(WINNT) || defined(_MINIX_VMD)
1164 # define d_fileno d_ino
1168 xgetcwd(pathname
, pathlen
)
1175 struct stat st_root
, st_cur
, st_next
, st_dotdot
;
1176 char pathbuf
[MAXPATHLEN
], nextpathbuf
[MAXPATHLEN
* 2];
1177 char *pathptr
, *nextpathptr
, *cur_name_add
;
1180 /* find the inode of root */
1181 if (stat("/", &st_root
) == -1) {
1182 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 23,
1183 "getcwd: Cannot stat \"/\" (%s)"),
1187 pathbuf
[MAXPATHLEN
- 1] = '\0';
1188 pathptr
= &pathbuf
[MAXPATHLEN
- 1];
1189 nextpathbuf
[MAXPATHLEN
- 1] = '\0';
1190 cur_name_add
= nextpathptr
= &nextpathbuf
[MAXPATHLEN
- 1];
1192 /* find the inode of the current directory */
1193 if (lstat(".", &st_cur
) == -1) {
1194 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 24,
1195 "getcwd: Cannot stat \".\" (%s)"),
1199 nextpathptr
= strnrcpy(nextpathptr
, "../", nextpathptr
- nextpathbuf
);
1201 /* Descend to root */
1204 /* look if we found root yet */
1205 if (st_cur
.st_ino
== st_root
.st_ino
&&
1206 DEV_DEV_COMPARE(st_cur
.st_dev
, st_root
.st_dev
)) {
1207 (void) strncpy(pathname
, *pathptr
!= '/' ? "/" : pathptr
, pathlen
);
1208 pathname
[pathlen
- 1] = '\0';
1212 /* open the parent directory */
1213 if (stat(nextpathptr
, &st_dotdot
) == -1) {
1214 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 25,
1215 "getcwd: Cannot stat directory \"%s\" (%s)"),
1216 nextpathptr
, strerror(errno
));
1219 if ((dp
= opendir(nextpathptr
)) == NULL
) {
1220 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 26,
1221 "getcwd: Cannot open directory \"%s\" (%s)"),
1222 nextpathptr
, strerror(errno
));
1226 /* look in the parent for the entry with the same inode */
1227 if (DEV_DEV_COMPARE(st_dotdot
.st_dev
, st_cur
.st_dev
)) {
1228 /* Parent has same device. No need to stat every member */
1229 for (d
= readdir(dp
); d
!= NULL
; d
= readdir(dp
)) {
1231 if (((unsigned long)d
->d_fileno
& 0xffff) == st_cur
.st_ino
)
1234 if (d
->d_fileno
== st_cur
.st_ino
)
1241 * Parent has a different device. This is a mount point so we
1242 * need to stat every member
1244 for (d
= readdir(dp
); d
!= NULL
; d
= readdir(dp
)) {
1245 if (ISDOT(d
->d_name
) || ISDOTDOT(d
->d_name
))
1247 (void)strncpy(cur_name_add
, d
->d_name
,
1248 (size_t) (&nextpathbuf
[sizeof(nextpathbuf
) - 1] - cur_name_add
));
1249 if (lstat(nextpathptr
, &st_next
) == -1) {
1251 * We might not be able to stat() some path components
1252 * if we are using afs, but this is not an error as
1253 * long as we find the one we need; we also save the
1254 * first error to report it if we don't finally succeed.
1256 if (save_errno
== 0)
1260 /* check if we found it yet */
1261 if (st_next
.st_ino
== st_cur
.st_ino
&&
1262 DEV_DEV_COMPARE(st_next
.st_dev
, st_cur
.st_dev
))
1267 (void) xsnprintf(pathname
, pathlen
, CGETS(23, 27,
1268 "getcwd: Cannot find \".\" in \"..\" (%s)"),
1269 strerror(save_errno
? save_errno
: ENOENT
));
1270 (void) closedir(dp
);
1276 pathptr
= strnrcpy(pathptr
, d
->d_name
, pathptr
- pathbuf
);
1277 pathptr
= strnrcpy(pathptr
, "/", pathptr
- pathbuf
);
1278 nextpathptr
= strnrcpy(nextpathptr
, "../", nextpathptr
- nextpathbuf
);
1279 *cur_name_add
= '\0';
1280 (void) closedir(dp
);
1283 # endif /* hp9000s500 */
1286 * Like strncpy, going backwards and returning the new pointer
1289 strnrcpy(ptr
, str
, siz
)
1290 register char *ptr
, *str
;
1293 register int len
= strlen(str
);
1297 while (len
&& siz
--)
1298 *--ptr
= str
[--len
];
1301 } /* end strnrcpy */
1308 #include <apollo/base.h>
1309 #include <apollo/loader.h>
1310 #include <apollo/error.h>
1317 static char buf
[BUFSIZE
];
1318 short e_subl
, e_modl
, e_codel
;
1319 error_$string_t e_sub
, e_mod
, e_code
;
1321 error_$
get_text(*st
, e_sub
, &e_subl
, e_mod
, &e_modl
, e_code
, &e_codel
);
1322 e_sub
[e_subl
] = '\0';
1323 e_code
[e_codel
] = '\0';
1324 e_mod
[e_modl
] = '\0';
1325 (void) xsnprintf(buf
, sizeof(buf
), "%s (%s/%s)", e_code
, e_sub
, e_mod
);
1334 short len
= Strlen(s
);
1338 loader_$
inlib(t
= short2str(s
), len
, &st
);
1339 if (st
.all
!= status_$ok
)
1340 stderror(ERR_SYSTEM
, t
, apperr(&st
));
1349 setname(short2str(*v
++));
1350 gflag
= 0, tglob(v
);
1354 stderror(ERR_NAME
| ERR_NOMATCH
);
1357 v
= gargv
= saveblk(v
);
1364 blkfree(gargv
), gargv
= 0;
1371 if (eq(v
, STRbsd43
))
1373 else if (eq(v
, STRsys53
))
1376 stderror(ERR_NAME
| ERR_SYSTEM
, short2str(v
),
1377 CGETS(23, 28, "Invalid system type"));
1390 setname(short2str(*v
++));
1392 if (!(p
= tgetenv(STRSYSTYPE
)))
1393 stderror(ERR_NAME
| ERR_STRING
,
1394 CGETS(23, 29, "System type is not set"));
1398 tsetenv(STRSYSTYPE
, getv(*v
) ? STRbsd43
: STRsys53
);
1404 * Many thanks to rees@citi.umich.edu (Jim Rees) and
1405 * mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
1406 * For figuring out how to do this... I could have never done
1407 * it without their help.
1409 typedef short enum {
1412 name_$node_dir_type
,
1421 name_$dir_type_t dirtype
= name_$node_dir_type
;
1427 setname(short2str(*v
++));
1429 name
= short2str(*v
);
1430 namelen
= strlen(name
);
1432 name_$
resolve(name
, &namelen
, &uid
, &st
);
1433 if (st
.all
!= status_$ok
)
1434 stderror(ERR_SYSTEM
, name
, apperr(&st
));
1436 name_$
set_diru(&uid
, "", &namelen
, &dirtype
, &st
);
1437 if (st
.all
!= status_$ok
)
1438 stderror(ERR_SYSTEM
, name
, apperr(&st
));
1445 static int res
= -1;
1446 static status_$t st
;
1458 st
.all
= status_$ok
;
1461 res
= stream_$
isavt(&strm
, &st
);
1465 if (st
.all
!= status_$ok
)
1466 stderror(ERR_SYSTEM
, "stream_$isavt", apperr(&st
));