#include "tcb.h" #include #include #include #include #include #include #include #include #include #ifdef linux #include #include #else #include #endif linux static struct { int sfd; char path[N_line]; } Tcb; static void usage(char tcb[], char version[]) { char *cp; static char tmp[256]; memcpy(tmp, version, 80); *strchr(tmp, '\n') = '\0'; if ((cp = strchr(tmp, '\n'))) *cp = '\0'; fprintf(stderr, "Usage: %s\n", tcb); fprintf(stderr, " %s [-?]\n", tcb); #if defined(linux) fprintf(stderr, " %s [-1] ... [-9]\n", tcb); fprintf(stderr, " %s [-8] [-9] [program] [option]\n", tcb); #elif defined (__FreeBSD__) fprintf(stderr, " %s [-1] ... [-3]\n", tcb); #endif fprintf(stderr, " %s [directory]\n", tcb); fprintf(stderr, " %s [file] [< file]\n", tcb); fprintf(stderr, "%s\n", tmp); } static void main_pipe(int dummy) { if (Tcb.sfd) { close(Tcb.sfd); Tcb.sfd = 0; unlink(Tcb.path); } free_S(); exit(0); } static int set_path(char dir[], char name[]) { int f_M, i; struct stat st; if (*name != '/') { char *p = alloca(strlen(dir) + strlen(name) + 1); strcpy(p, dir); strcat(p, name); strcpy(name, p); /* full path */ } stat(name, &st); if ((i = strchr(name, '\0')[-1] == '/') || S_ISDIR(st.st_mode)) { f_M = T_dir; if (!i) strcat(name, "/"); } else f_M = T_file; erase_dot(name); strcpy(dir, name); get_dir(dir); return f_M; } static void from_shell(char *name, int pid, int f, char *mess) { char str[N_pipe+1]; int i, c, len, row; u_char m; get_winsize(&row, &c); sprintf(&strstr(mess, "/s.")[3], "%d.%d", (int)getuid() , (pid) ? pid : (int)getppid()); if (!name && (!f || f == 'p')) { struct sockaddr_un cli_addr, serv_addr; int sfd, clilen; m = T_pipe2; signal(SIGPIPE, main_pipe); strcpy(Tcb.path, mess); if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "%s: Can't open socket\n", s_S(S_tcb)); free_S(); exit(0); } serv_addr.sun_family = AF_UNIX; strcpy(serv_addr.sun_path, Tcb.path); unlink(Tcb.path); if (bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) >= 0) { clilen = sizeof(cli_addr); if (listen(sfd, 5) >= 0) if ((Tcb.sfd = accept(sfd, (struct sockaddr *)&cli_addr, &clilen)) >= 0) { send(Tcb.sfd, &m, sizeof(u_char), 0); c = getpid(); send(Tcb.sfd, &c, sizeof(int), 0); for (i = row-1; i && (c = fgetc(stdin)) != EOF; ) { send(Tcb.sfd, &c, 1, 0); if (c == '\n') i--; else if (c == '\r') { if ((c = fgetc(stdin)) == '\n') i--; send(Tcb.sfd, &c, 1, 0); } } if (c != EOF) do { c = fread(str, 1, N_pipe, stdin); send(Tcb.sfd, str, c, 0); } while (c == N_pipe); close(Tcb.sfd); unlink(Tcb.path); } else perror("accept"); else perror("listen"); } else perror("bind"); } else { FILE *fp; char *cp, dir[N_line]; getcwd(dir, N_line); if (strchr(dir, '\0')[-1] != '/') strcat(dir, "/"); switch(f) { case 'u': m = M_du; break; case 'U': m = T_du2; break; default: if ((cp = strchr(name, '\r'))) *cp = '\0'; m = set_path(dir, name); if (access(name, F_OK) < 0) { printf("%s: %s: %s\n", s_S(S_tcb), name, strerror(ENOENT)); exit(1); } break; } sprintf(str, "%s.%s", mess, s_S(S_tcb)); fp = fopen(str, "w"); fwrite(&m, 1, sizeof(u_char), fp); len = strlen(dir) + 1; fwrite(&len, 1, sizeof(int), fp); fwrite(dir, 1, len, fp); if (m != M_du) { len = strlen(name) + 1; fwrite(&len, 1, sizeof(int), fp); fwrite(name, 1, len, fp); } fclose(fp); rename(str, mess); } free_S(); exit(0); } static int check_ps(int f_tty, int pid, char **err) { int n_pid, pv[4]; char n_tty[20], str[256]; FILE *fp; static char n[4]; static char *sp[] = { "ps", "grep", "tcb", n, }; if (f_tty) sprintf(sp[3], "\\-%d", f_tty); else strcpy(n_tty, "/dev/tty"); pipe(pv); if (!fork()) { pipe(&pv[2]); if (!fork()) { close(1); dup2(pv[3], 1); close(pv[3]); close(pv[2]); execlp(sp[0], sp[0], "a", NULL); } close(0); dup2(pv[2], 0); close(pv[3]); close(pv[2]); close(1); dup2(pv[1], 1); close(pv[1]); close(pv[0]); if (f_tty) execlp(sp[1], sp[1], sp[3], "-", NULL); else execlp(sp[1], sp[1], sp[2], "-", NULL); } close(pv[1]); fp = fdopen(pv[0], "r"); n_pid = 0; if (f_tty) { do { if (!fgets(str, 256, fp)) break; if (strstr(str, sp[2])) n_pid++; } while (n_pid < 2); if (n_pid == 2) fprintf(stderr, "%s -%d: Invalid terminal\n", sp[2], f_tty); else { fclose(fp); return 0; } } else { do { if (!fgets(str, 256, fp)) break; sscanf(str, "%d %s", &n_pid, &n_tty[8]); } while (n_pid != pid); if (!n_pid) fprintf(stderr, "Unknown error\n"); else { fprintf(stderr, "\n Already running on "); if (!strcmp(n_tty, ttyname(1))) fprintf(stderr, "this terminal.\n"); else fprintf(stderr, "tty%s.\n", &n_tty[8]); } } fclose(fp); return 1; } static void check_pl(int f_tty, char **err, char tcb[]) { struct stat st; int i, pid; FILE *fp; char *s_pid; if (!f_tty) { char *cp = getenv("HOME"); s_pid = alloca(strlen(cp) + strlen(tcb) + 6 + 1); strcpy(s_pid, cp); if (strchr(s_pid, '\0')[-1] != '/') strcat(s_pid, "/"); sprintf(strchr(s_pid, '\0'), ".%s/pid", tcb); if (!stat(s_pid, &st)) { fp = fopen(s_pid, "r"); fscanf(fp, "%d", &pid); fclose(fp); if (pid && !kill(pid, 0)) { struct stat old; stat(s_pid, &old); kill(pid, SIGCONT); fprintf(stderr, "%s: Process-ID %d ... ", tcb, pid); fflush(stdout); for (i = 6; i; i--) { stat(s_pid, &st); if (st.st_mtime != old.st_mtime) break; sleep(1); } if (i) { if (check_ps(0, pid, err)) { free_S(); exit(1); } } else unlink(s_pid); } } } else if (check_ps(f_tty, 0, err)) { free_S(); exit(1); } } #ifdef linux static void goto_tty(int ntty) { char n[7]; setenv("TCBVT", "", 1); sprintf(n, "tcb -%d", ntty); system(n); unsetenv("TCBVT"); } #endif linux void main(int argc, char *argv[]) { char pathname[N_line], args[N_line]; struct stat st; struct termios otty; static struct { u_int shell : 1; u_int tcb : 8; } f; int tfd; #if defined (linux) struct vt_stat vtstat; static char tty[] = "/dev/tty?"; static char **cmd; #elif defined (__FreeBSD__) static char tty[] = "/dev/ttyv?"; struct { int v_active; } vtstat; #endif int i, ntty0 = 0, ntty = 0; static char tcb[256]; static char tmp[N_line]; static char *err[] = { "Invalid option", "TCB environment variable is set", }; /* * f.tcb * & 0x80 : file manager (with history-list) * & 0x40 : file manager [directory] * & 0x20 : pager (stdin) * & 0x10 : pager [file] * & 0x04 : -? */ static char version[] = { #include "version.h" }; FILE *pin = EOP; conf(tmp, tcb, NULL, 0); if (stat(tmp, &st) < 0) { if (mkdir(tmp, 0) < 0) { fprintf(stderr, "%s: %s: %s\n", tcb, tmp, strerror(errno)); exit(1); } chmod(tmp, S_IRWXU|S_IRWXG|S_IRWXO); } else if (!S_ISDIR(st.st_mode) || access(tmp, R_OK|W_OK) < 0 ) { fprintf(stderr, "%s: %s: %s\n", tcb, tmp, strerror(errno)); exit(1); } sprintf(tmp, "%s/s.", tmp); *pathname = '\0'; if (!getenv("TCBVT") && tcgetattr(0, &otty) < 0) f.tcb |= 0x20; f.shell = getenv("TCB") != NULL; if (argc == 1) { if (f.shell) if (f.tcb & 0x20) from_shell(NULL, 0, 0, tmp); else { fprintf(stderr, "%s: %s\n", tcb, err[1]); exit(1); } else if (!(f.tcb & 0x20)) f.tcb |= 0x80; } else { while (*++argv) if (**argv == '-') switch(i = (*argv)[1]) { #ifdef linux case '0': ioctl(1, VT_GETSTATE, &vtstat); if (vtstat.v_active < 8) { usage(tcb, version); exit(1); } else { goto_tty(7); exit(0); } break; case '8': case '9': if (f.tcb & 0x20) continue; if (argv[1]) { f.tcb |= 0x01; check_pl(i - '0', err, tcb); ioctl(1, VT_GETSTATE, &vtstat); if (vtstat.v_active == i) { usage(tcb, version); exit(1); } tty[8] = i; ntty = tty[8]-'0'; sprintf(strchr(args, '\0'), " %s", *argv); for (cmd = &argv[1]; *argv; argv++) ; argv--; break; } #endif case '1': case '2': case '3': #ifdef linux case '4': case '5': case '6': case '7': #endif linux if (f.tcb & 0x20) continue; if (argv[1]) { fprintf(stderr, "%s -%c: %s\n", tcb, i, err[0]); exit(1); } if (!getenv("TCBVT") && fork()) exit(0); #if defined (linux) *strchr(tty, '?') = i; #elif defined(__FreeBSD__) *strchr(tty, '?') = i-1; #endif ntty0 = i - '0'; tfd = open(tty, O_RDWR); ioctl(tfd, VT_ACTIVATE, ntty0); close(tfd); exit(0); break; case 'p': if (!f.shell || !(f.tcb & 0x20)) { fprintf(stderr, "%s: %s -p\n", tcb, err[0]); usage(tcb, version); exit(1); } from_shell(NULL, atoi(argv[1]), i, tmp); break; case 'l': if (f.shell) { fprintf(stderr, "%s: %s\n", tcb, err[1]); exit(1); } f.tcb |= 0x80; strcpy(args, *argv); break; case 'u': case 'U': if (!f.shell) { fprintf(stderr, "%s: %s -%c\n", tcb, err[0], i); usage(tcb, version); exit(1); } from_shell(NULL, 0, i, tmp); break; case '?': f.tcb &= ~(0x80 | 0x20); f.tcb |= 0x04; sprintf(strchr(args, '\0'), " %s", *argv); break; case 'h': usage(tcb, version); exit(0); break; default: fprintf(stderr, "%s: %s -%c\n", tcb, err[0], i); usage(tcb, version); exit(1); break; } else if (f.tcb & 0x20) continue; else if (stat(*argv, &st) < 0 || access(*argv, R_OK) < 0) { fprintf(stderr, "%s: %s: %s\n", tcb, *argv, strerror(errno)); exit(1); } else { if (f.shell) from_shell(*argv, 0, 0, tmp); f.tcb &= ~0x80; f.tcb |= (S_ISDIR(st.st_mode)) ? 0x40 : 0x10; strcpy(pathname, *argv); sprintf(strchr(args, '\0'), " %s", *argv); } } #if defined(linux) ioctl(1, VT_GETSTATE, &vtstat); ntty0 = vtstat.v_active; if (f.tcb & 0x01) { if (fork()) exit(0); close(0); close(1); close(2); setsid(); if ((tfd = open(tty, O_RDWR, 0)) < 0) { perror(tty); exit(2); } dup(0); dup(0); if (ioctl(tfd, VT_ACTIVATE, ntty) < 0) { perror("2"); exit(1); } while (1) { ioctl(tfd, VT_GETSTATE, &vtstat); if (vtstat.v_active == ntty) break; usleep(10000); } if (cmd) { if (!fork()) execvp(*cmd, cmd); wait(0); close(tfd); goto_tty(ntty0); } exit(0); } #elif defined(__FreeBSD__) if (f.tcb == 0x01 && f.shell) { fprintf(stderr, "%s: %s\n", tcb, err[1]); exit(1); } ntty0 = ntty; #endif if (f.tcb & 0x20) { strcpy(pathname, s_P(P_mode)[T_pipe]); pin = stdin; } if (f.shell) { fprintf(stderr, "%s: %s\n", tcb, err[1]); free_S(); exit(1); } if (f.tcb & 0x80) check_pl(0, err, tcb); signal(SIGCHLD, sig_child); if (conf(tmp, args, version, f.tcb) < 0) { free_S(); exit(1); } if (vt_set(f.tcb) < 0) { free_S(); exit(1); } save_signal(f.tcb); sprintf(tmp, "tcb v%s", &(strchr(version, ' '))[1]); *strchr(tmp, '-') = '\0'; setenv("TCB", tmp, 1); if (access(s_S(S_tcbrc), F_OK) < 0) { fprintf(stderr, "%s: %s: %s\n", tcb, s_S(S_tcbrc), strerror(ENOENT)); free_S(); exit(1); } print_stderr(s_S(S_stderr)); if (vt_init(0) < 0) { free_S(); print_stderr(NULL); exit(1); } #if defined(linux) ioctl(1, VT_GETSTATE, &vtstat); #elif defined(__FreeBSD__) ioctl(1, VT_GETACTIVE, &vtstat.v_active); #endif ntty = vtstat.v_active; menu(pathname, (ntty) ? ntty : ntty0, pin); exit_tcb(ntty0); print_stderr(NULL); exit(printALLOC(NULL)); } void exit_tcb(int ntty0)/*tcb*/ { signal(SIGSEGV, SIG_DFL); if (is_fm()) { start_shell(0, 0, NULL, NULL, NULL, NULL); if (vt_set(0) & 0x80) { int i; char str[256]; strcpy(str, s_S(S_write)); i = ichrstr(str, 0, "w.tcb"); strcpy(&str[i-1], "shell"); rename(s_S(S_log), str); strcpy(&str[i-1], "error"); rename(s_S(S_error), str); } } unlink_file(); if (get_ntty() >= 8) write(1, "\033[H\033[J", 6); vt_init(-3); #ifdef linux if (vt_set(0) & 0x01) goto_tty(ntty0); #endif linux free_S(); free_h(NULL); } #ifdef __FreeBSD__ void sig_child(int dummy) { int pid; int status; while ((pid = wait3((int*)&status, WNOHANG, (struct rusage *)0)) > 0) ; } #endif __FreeBSD__ int get_ntty(void)/*tcb*/ { #if defined (linux) struct vt_stat vtstat; #elif defined (__FreeBSD__) struct { int v_active; } vtstat; #endif #if defined (linux) ioctl(vt_tfd(0), VT_GETSTATE, &vtstat); #elif defined (__FreeBSD__) ioctl(vt_tfd(0), VT_GETACTIVE, &vtstat.v_active); #endif return vtstat.v_active; }