Хрестоматия по программированию на Си в Unix
register eacces = 0;
char fullpath[256]; /* полное имя программы */
firstfound = NULL;
if((path = getenv("PATH")) == NULL )
path = ".:/bin:/usr/bin:/etc";
/* имя: короткое или путь уже задан ? */
cp = strchr(progr, '/') ? "" : path;
do{ /* пробуем разные варианты */
cp = execat(cp, progr, fullpath);
retry:
fprintf(stderr, "пробуем \"%s\"\n", fullpath );
execve(fullpath, av, envp);
/* если программа запустилась, то на этом месте данный
* процесс заменился новой программой. Иначе - ошибка. */
switch( errno ){ /* какова причина неудачи ? */
case ENOEXEC: /* это командный файл */
callshell(fullpath, av, envp);
return (-1);
case ETXTBSY: /* файл записывается */
if( ++try > 5 ) return (-1);
sleep(try); goto retry;
case EACCES: /* не имеете права */
if(firstfound == NULL)
firstfound = strdup(fullpath);
eacces++; break;
case ENOMEM: /* программа не лезет в память */
case E2BIG:
return (-1);
}
}while( cp );
if( eacces ) errno = EACCES;
return (-1);
}
/* Склейка очередной компоненты path и имени программы name */
static char *execat(path, name, buf)
register char *path, *name;
char *buf; /* где будет результат */
{
register char *s = buf;
while(*path && *path != LIM )
*s++ = *path++; /* имя каталога */
if( s != buf ) *s++ = '/';
while( *name )
*s++ = *name++; /* имя программы */
*s = '\0';
return ( *path ? ++path /* пропустив LIM */ : NULL );
}
А. Богатырев, 1992-95 - 276 - Си в UNIX
/* Запуск командного файла при помощи вызова интерпретатора */
void callshell(progr, av, envp) char *progr, **av, **envp;
{
register i; char *sh; char *newav[MAXARGS+2];
int fd; char first = 0;
if((fd = open(progr, O_RDONLY)) < 0 )
sh = "/bin/sh";
else{
read(fd, &first, 1); close(fd);
sh = (first == '#') ? "/bin/csh" : "/bin/sh";
}
newav[0] = "Shellscript"; newav[1] = progr;
for(i=1; av[i]; i++)
newav[i+1] = av[i];
newav[i+1] = NULL;
printf( "Вызываем %s\n", sh );
execve(sh, newav, envp);
}
/* Ожидать окончания всех процессов, выдать причины смерти. */
void dowait(){
int ws; int pid;
while((pid = wait( &ws)) > 0 ){
if( WIFEXITED(ws)){
printf( "Процесс %d умер с кодом %d\n",
pid, WEXITSTATUS(ws));
}else if( WIFSIGNALED(ws)){
printf( "Процесс %d убит сигналом %d\n",
pid, WTERMSIG(ws));
if(WCOREDUMP(ws)) printf( "Образовался core\n" );
/* core - образ памяти процесса для отладчика adb */
}else if( WIFSTOPPED(ws)){
printf( "Процесс %d остановлен сигналом %d\n",
pid, WSTOPSIG(ws));
}
}
}
А. Богатырев, 1992-95 - 277 - Си в UNIX
/* Расширение шаблонов имен. Это упрощенная версия, которая
* расширяет имена только в текущем каталоге.
*/
void glob(dir, args, indx, str /* что расширять */, quote )
char *args[], *dir; int *indx; char *str;
char quote; /* кавычки, в которые заключена строка str */
{
static char globchars[] = "*?[";
char *p; char **start = &args[ *indx ];
short nglobbed = 0;
register struct dirent *dirbuf;
DIR *fd; extern DIR *opendir();
/* Затычка для отмены глоббинга: */
if( *str == '\\' ){ str++; goto noGlob; }
/* Обработка переменных $NAME */
if( *str == '$' && quote != '\'' ){
char *s = getenv(str+1);
if( s ) str = s;
}
/* Анализ: требуется ли глоббинг */
if( quote ) goto noGlob;
for( p=str; *p; p++ ) /* Есть ли символы шаблона? */
if( strchr(globchars, *p))
goto doGlobbing;
noGlob:
args[ (*indx)++ ] = strdup(str);
return;
doGlobbing:
if((fd = opendir (dir)) == NULL){
fprintf(stderr, "Can't read %s\n", dir); return;
}
while ((dirbuf = readdir (fd)) != NULL ) {
if (dirbuf->d_ino == 0) continue;
if (strcmp (dirbuf->d_name, ".") == 0 ||
strcmp (dirbuf->d_name, "..") == 0) continue;
if( match( dirbuf->d_name, str)){
args[ (*indx)++ ] = strdup(dirbuf->d_name);
nglobbed++;
}
}
closedir(fd);
if( !nglobbed){
printf( "%s: no match\n", str);
goto noGlob;
}else{ /* отсортировать */
qsort(start, nglobbed, sizeof (char *), cmps);
}
}
А. Богатырев, 1992-95 - 278 - Си в UNIX
/* Разбор командной строки */
int parse(s) register char *s;
{
int i; register char *p;
char tmp[80]; /* очередной аргумент */
char c;
/* очистка старых аргументов */
for(i=0; arg[i]; i++) free(arg[i]), arg[i] = NULL;
if( fin ) free(fin ), fin = NULL;
if( fout ) free(fout), fout = NULL;
rout = 0;
/* разбор строки */
for( i=0 ;; ){
char quote = '\0';
/* пропуск пробелов - разделителей слов */
while((c = *s) && isspace(c)) s++;
if( !c ) break;
/* очередное слово */
p = tmp;
if(*s == '\'' || *s == '"' ){
/* аргумент в кавычках */
quote = *s++; /* символ кавычки */
while((c = *s) != '\0' && c != quote){
if( c == '\\' ){ /* заэкранировано */
c = *++s;
if( !c ) break;
}
*p++ = c; ++s;
}
if(c == '\0')
fprintf(stderr, "Нет закрывающей кавычки %c\n", quote);
else s++; /* проигнорировать кавычку на конце */
А. Богатырев, 1992-95 - 279 - Си в UNIX
} else
while((c = *s) && !isspace(c)){
if(c == '\\') /* заэкранировано */
if( !(c = *++s))
break /* while */;
*p++ = c; s++;
}
*p = '\0';
/* Проверить, не есть ли это перенаправление
* ввода/вывода. В отличие от sh и csh
* здесь надо писать >ФАЙЛ <ФАЙЛ
* >< вплотную к имени файла.
*/
p = tmp; /* очередное слово */
if( *p == '>'){ /* перенаправлен вывод */
p++;
if( fout ) free(fout), rout = 0; /* уже было */
if( *p == '>' ){ rout |= APPEND; p++; }
if( *p == '&' ){ rout |= ERRTOO; p++; }
if( !*p ){
fprintf(stderr, "Нет имени для >\n");
fout = NULL; rout = 0;
} else fout = strdup(p);
} else if( *p == '<' ){ /* перенаправлен ввод */
p++;
if( fin ) free(fin); /* уже было */
if( !*p ){
fprintf(stderr, "Нет имени для <\n");
fin = NULL;
} else fin = strdup(p);
} else /* добавить имена к аргументам */
glob( ".", arg, &i, p, quote );
}
arg[i] = NULL; return i;
}
/* Установить имя пользователя */
void setuser(){
int uid = getuid(); /* номер пользователя, запустившего Шелл */
char *user = "mr. Nobody"; /* имя пользователя */
char *home = "/tmp"; /* его домашний каталог */
struct passwd *pp = getpwuid( uid );
if( pp != NULL ){
if(pp->pw_name && *pp->pw_name ) user = pp->pw_name;
if( *pp->pw_dir ) home = pp->pw_dir;
}
setenv("USER", user); setenv("HOME", home);
}
void setcwd(){ /* Установить имя текущего каталога */
char cwd[512];
getwd(cwd); setenv( "CWD", cwd );
}
void main(ac, av, ev) char *av[], *ev[]; {
int argc; /* количество аргументов */
char *prompt; /* приглашение */
setuser(); setcwd();
signal(SIGINT, SIG_IGN);
setbuf(stdout, NULL); /* отменить буферизацию */
for(;;){
prompt = getenv( "prompt" ); /* setenv prompt -->\ */
printf( prompt ? prompt : "@ ");/* приглашение */
if( gets(cmd) == NULL /* at EOF */ ) exit(0);
argc = parse(cmd);
if( !argc) continue;
if( !strcmp(arg[0], "exit" )) exit(0);
if( !strcmp(arg[0], "cd" )){
char *d = (argc==1) ? getenv("HOME"):arg[1];
if(chdir(d) < 0)
printf( "Не могу войти в %s\n", d );
else setcwd();
continue;
}
if( !strcmp(arg[0], "echo" )){
register i; FILE *fp;
if( fout ){
if((fp = fopen(fout, rout & APPEND ? "a":"w"))
== NULL) continue;
} else fp = stdout;
for(i=1; i < argc; i++ )
fprintf( fp, "%s%s", arg[i], i == argc-1 ? "\n":" ");
if( fp != stdout ) fclose(fp);
continue;
}
if( !strcmp(arg[0], "setenv" )){
if( argc == 1 ) printenv();
else if( argc == 2 ) setenv( arg[1], "" );
else setenv( arg[1], arg[2]);
continue;
}
cmdExec(arg[0], (char **) arg, environ, fin, fout, rout);