summaryrefslogtreecommitdiff
path: root/libc/tests/ft.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/tests/ft.c')
-rw-r--r--libc/tests/ft.c1217
1 files changed, 1217 insertions, 0 deletions
diff --git a/libc/tests/ft.c b/libc/tests/ft.c
new file mode 100644
index 0000000..6456d0b
--- /dev/null
+++ b/libc/tests/ft.c
@@ -0,0 +1,1217 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This program is distributed under the GNU General Public License.
+ */
+
+/*
+ * File Tool, This program is a collection of basic file tools
+ * it includes cat, cp, ln, mkdir, mknod, chmod, chown, mv, rm
+ *
+ * Links may be used to call it under any of these names.
+ */
+#include <stdio.h>
+#ifdef __STDC__
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <utime.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef __BCC__X
+#undef S_IFLNK
+#undef S_IFSOCK
+#endif
+
+#ifdef S_IFSOCK
+#include <sys/socket.h>
+#endif
+#ifndef S_IFLNK
+#define lstat stat
+#endif
+
+/* Ansi prototypes */
+#ifdef __STDC__
+#define PR(x) x
+#else
+#define PR(x) ()
+#endif
+
+void main PR((int argc, char ** argv));
+int select_command PR((char * argv));
+void do_prep PR((void));
+void do_post PR((void));
+void execute PR((char * dname, char * fname));
+int exec_for_subdir PR((char * dname));
+void exec_for_item PR((int when, char * fname));
+void parse_perms PR((char * prefix, char * ustring));
+int edit_mode PR((int mode, char * mode_str));
+int cmd_ft PR((char * fname));
+int cmd_mkfifo PR((char * fname));
+int cmd_mksock PR((char * fname));
+int cmd_rm PR((char * fname));
+void build_dest PR((char * dest, char * name, char * newpath));
+int strisdigit PR((char * str));
+int cmd_mv PR((char * fname));
+int cmd_ln PR((char * fname));
+int cmd_cp PR((char * fname));
+int copy_modes PR((char * file));
+int copy_file PR((char * source, char * dest));
+void Usage PR((void));
+int cmd_mkdir PR((char * dirname));
+int cmd_mknod PR((void));
+int warn_func PR((int enumber, char * estr, char * eobj));
+int error_func PR((int enumber, char * estr, char * eobj));
+
+#define warning(x,y,z) ( Line_no = __LINE__, warn_func(x,y,z))
+#define error(x,y,z) ( Line_no = __LINE__, error_func(x,y,z))
+int Line_no = -1;
+
+#define DO_BDIR 0x0010 /* Do Dir before contents */
+#define DO_ADIR 0x0020 /* Do Dir after contents */
+#define DO_MCOPY 0x0040 /* Preserve modes flag forced */
+#define OK_DIR 0x0080 /* Directorys OK even if no flg_recurse */
+#define IGN_LNK 0x0100 /* Not interested in symlinks */
+#define NO_SOURCE 0x0200 /* Named files created */
+#define OK_NO_SOURCE 0x0400 /* Don't need the source */
+
+#define CMD_FT (0+OK_DIR+DO_BDIR)
+#define CMD_CAT (1+IGN_LNK)
+#define CMD_CHGRP (2+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CHMOD (3+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CHOWN (4+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CP (5+IGN_LNK)
+#define CMD_EXTAR (6+DO_MCOPY+DO_BDIR)
+#define CMD_INSTALL (7+DO_MCOPY)
+#define CMD_LN (8+IGN_LNK+DO_BDIR)
+#define CMD_MKDIR (9+NO_SOURCE)
+#define CMD_MKFIFO (10+NO_SOURCE)
+#define CMD_MKSOCK (11+NO_SOURCE)
+#define CMD_MKNOD (12+NO_SOURCE)
+#define CMD_MV (13+DO_MCOPY+OK_DIR+DO_BDIR)
+#define CMD_RM (14+DO_ADIR)
+
+struct {
+ char * name;
+ int cmd;
+ int argpat;
+ char * opts;
+} command_list[] =
+{
+ { "ft", CMD_FT, 0, "-Rv" },
+ { "cat", CMD_CAT, 0, "uR" },
+ { "chgrp", CMD_CHGRP, 1, "vfR" },
+ { "chmod", CMD_CHMOD, 1, "vfR" },
+ { "chown", CMD_CHOWN, 1, "vfR" },
+ { "cp", CMD_CP, -1, "vifRrpsd" },
+ { "extar", CMD_EXTAR, 1, "" },
+ { "install", CMD_INSTALL, -1, "cdso:g:m:" },
+ { "ln", CMD_LN, -1, "vifs" },
+ { "mkdir", CMD_MKDIR, 0, "m:" },
+ { "mkfifo", CMD_MKFIFO, 0, "m:" },
+#ifdef S_IFSOCK
+ { "mksock", CMD_MKSOCK, 0, "m:" },
+#endif
+ { "mknod", CMD_MKNOD, 4, "m:" },
+ { "mv", CMD_MV, -1, "vif" },
+ { "rm", CMD_RM, 0, "vifr" },
+ { 0 }
+};
+
+int cmd_arg = 0;
+int cmd_tok = CMD_FT;
+char * cmd_opt = "-";
+char * cmd_string = 0; /* the first (or last) arg where special */
+char * prog_name = "";
+
+char ** flist = 0;
+int fcount = 0;
+int add_base=0;
+char * or_name = 0;
+int or_offset = 0;
+
+int flg_recurse = 0;
+int flg_verbose = 1;
+int flg_preserve= 0;
+int flg_mkpdir = 0;
+int flg_noderef = 0;
+int flg_symlink = 0;
+int flg_exestrip= 0;
+
+int flg_r, flg_force;
+char *str_o, *str_g, *str_m;
+
+/* Things to set on the new file */
+int set_user = -1;
+int set_group = -1;
+int set_mode = -1;
+time_t set_time = -1;
+char mode_str[32] = "";
+int u_mask = 0; /* 07777 altered by umask() */
+
+struct stat cur_file_stat;
+struct stat dest_item;
+struct stat access_stat;
+
+int done_something = 0;
+
+void
+main(argc, argv)
+int argc; char ** argv;
+{
+ int ar;
+ (void) select_command(argv[0]);
+
+ for(ar=1;
+ argv[ar] && argv[ar][0] == '-' && argv[ar][1];
+ ar++)
+ {
+ char * p = argv[ar]+1;
+ /* For symbolic changes of the form -rwx */
+ if( cmd_tok == CMD_CHMOD && strchr("rwx", *p) != 0 ) break;
+ while(*p)
+ {
+ char * ap=0, *av=0;
+ char ch;
+ /* Is it a valid opt for this cmd */
+ if(*p == ':' || (ap=strchr(cmd_opt, *p)) == 0) Usage();
+
+ /* Got an argument ? */
+ if(ap[1] == ':')
+ {
+ if(!argv[ar+1]) Usage();
+ av = argv[++ar];
+ }
+
+ if( (ch = *p) == '-' )
+ {
+ if( (ch=select_command(p)) < 0 ) Usage();
+ }
+ switch(ch)
+ {
+ case '\0': break;
+ case 'r':
+ case 'R': flg_recurse++; break;
+ case 'v': flg_verbose++; break;
+ case 'p': if(cmd_tok == CMD_MKDIR) flg_mkpdir++;
+ else flg_preserve++;
+ break;
+ case 'd': if(cmd_tok == CMD_INSTALL)
+ { flg_mkpdir++; cmd_arg=0; } /* Special mkdir */
+ else flg_noderef++; /* cmd_copy */
+ break;
+
+ case 'f': flg_force++; flg_verbose=0; break;
+ case 'o': str_o = av; break;
+ case 'g': str_g = av; break;
+ case 'm': str_m = av; break;
+
+ case 's': flg_symlink++;
+ if( cmd_tok == CMD_LN) cmd_tok |= OK_DIR+OK_NO_SOURCE;
+ break;
+ }
+ if(*p == '-') break;
+ p++;
+ }
+ }
+
+ switch(cmd_arg)
+ {
+ case 1:
+ if( ar >= argc ) Usage();
+ cmd_string = argv[ar++];
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ case 0:
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ case -1:
+ if( ar >= argc ) Usage();
+ cmd_string = argv[argc-1];
+ fcount = argc-ar-1;
+ flist = argv+ar;
+ break;
+ default:
+ if( ar != argc-cmd_arg ) Usage();
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ }
+
+ do_prep();
+
+ for(ar=0; ar<fcount; ar++)
+ {
+ done_something=1;
+ or_name = flist[ar]; or_offset = strlen(or_name)+1;
+ execute(flist[ar], (char*)0);
+ }
+
+ do_post();
+
+ if( !done_something )
+ {
+ if( cmd_tok == CMD_CAT )
+ execute("-", (char*)0);
+ else
+ Usage();
+ }
+ exit(0);
+}
+
+int select_command(argv)
+char * argv;
+{
+ int ar;
+ char *p, *s;
+ prog_name = argv;
+ for(ar=0; command_list[ar].name; ar++)
+ {
+ p = strrchr(argv, '-'); if(p) p++; else p=argv;
+ s = strrchr(p, '/'); if(s) s++; else s=p;
+ if( strcmp(s, command_list[ar].name) == 0 )
+ {
+ cmd_arg = command_list[ar].argpat;
+ cmd_tok = command_list[ar].cmd;
+ cmd_opt = command_list[ar].opts;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void do_prep()
+{
+ char * prefix = "::";
+
+ u_mask = umask(077);
+ umask(u_mask);
+ u_mask = (07777&(~u_mask));
+
+ if(cmd_tok&DO_MCOPY) flg_preserve++;
+ if(str_m) parse_perms(prefix, str_m);
+
+ switch(cmd_tok)
+ {
+ /* mknod is very different */
+ case CMD_MKNOD: cmd_mknod(); exit(0); break;
+
+ case CMD_CP:
+ if(strcmp(cmd_string, "-") == 0)
+ {
+ cmd_tok = CMD_CAT;
+ cmd_arg = 0;
+ break;
+ }
+ if(flg_symlink)
+ {
+ cmd_tok = CMD_LN+OK_DIR+OK_NO_SOURCE;
+ flg_preserve = 0;
+ }
+ break;
+
+ case CMD_CHOWN: prefix++;
+ case CMD_CHGRP: prefix++;
+ case CMD_CHMOD:
+ parse_perms(prefix, cmd_string);
+ set_time = 0;
+ break;
+ case CMD_INSTALL:
+ flg_exestrip = flg_symlink;
+ flg_symlink = 0;
+ if(str_o) parse_perms(prefix+2, str_o);
+ if(str_g) parse_perms(prefix+1, str_g);
+ if(flg_mkpdir) cmd_tok = CMD_MKDIR;
+ else
+ {
+ cmd_tok = CMD_CP;
+ flg_preserve = 1;
+ }
+ break;
+ }
+
+#ifndef S_IFLNK
+ if(flg_symlink)
+ {
+ error(0, "No support for symlinks available:", cmd_string);
+ exit(1);
+ }
+#endif
+
+ /* Are we transfering many to one ? Then it must be a directory */
+ if(cmd_arg == -1)
+ {
+ if( stat(cmd_string, &dest_item) == -1)
+ {
+ if( fcount > 1 )
+ {
+ if( cmd_mkdir(cmd_string) < 0 )
+ exit(1);
+ stat(cmd_string, &dest_item);
+ add_base = 1;
+ }
+ }
+ else
+ {
+ if( !S_ISDIR(dest_item.st_mode) )
+ {
+ if( fcount > 1 )
+ {
+ error(0, "Destination must be a directory:", cmd_string);
+ exit(1);
+ }
+ }
+ else add_base = 1;
+ }
+ }
+}
+
+void do_post()
+{
+ /* Oh! It seems there's nothing to do, ah well. */
+}
+
+void execute(dname, fname)
+char * dname; char * fname;
+{
+ char * buf;
+ if( strcmp(dname, "-") == 0 )
+ {
+ exec_for_item(0, dname);
+ return;
+ }
+ if( fname )
+ {
+ buf = alloca(strlen(dname) + strlen(fname) + 4);
+ if( buf == 0 )
+ {
+ error(errno, "Can't allocate memory for path beyond", dname);
+ return ;
+ }
+ strcpy(buf, dname);
+ if(strcmp(dname, "/")) strcat(buf, "/");
+ strcat(buf, fname);
+ }
+ else buf = dname;
+
+ if( lstat(buf, &cur_file_stat) == -1 )
+ {
+ if( cmd_tok&(NO_SOURCE|OK_NO_SOURCE) )
+ exec_for_item(0, buf);
+ else
+ warning(errno, "", buf);
+ return;
+ }
+ if( !flg_force && ( cmd_tok&NO_SOURCE ))
+ {
+ error(EEXIST, "", buf);
+ return;
+ }
+
+ if( S_ISDIR(cur_file_stat.st_mode))
+ {
+ if( (cmd_tok&OK_DIR) || flg_recurse )
+ (void) exec_for_subdir(buf);
+ else
+ error(EISDIR, "", buf);
+ return;
+ }
+
+#ifdef S_IFLNK
+ if( S_ISLNK(cur_file_stat.st_mode))
+ {
+ /* Links are special */
+ if( cmd_tok&IGN_LNK )
+ {
+ if( stat(buf, &cur_file_stat) == -1 )
+ {
+ warning(errno, "", buf);
+ return;
+ }
+ }
+ }
+#endif
+ exec_for_item(0, buf);
+}
+
+int exec_for_subdir(dname)
+char * dname;
+{
+ DIR * dfd;
+ struct dirent * ent;
+ int old_mode = -1;
+
+ if( cmd_tok&DO_BDIR ) exec_for_item(-1, dname);
+
+ if( flg_recurse )
+ {
+ dfd = opendir(dname);
+
+ if( dfd == 0 && errno == EACCES && flg_force )
+ {
+ old_mode = (cur_file_stat.st_mode & 07777);
+ if( chmod(dname, (0700|old_mode)) )
+ return error(errno, "Can't unlock", dname);
+
+ dfd = opendir(dname);
+ }
+ if( dfd == 0 ) return error(errno, "Can't open", dname);
+
+ while((ent=readdir(dfd)))
+ {
+ if( strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 )
+ continue;
+
+ alloca(0); /* Free up if using fake version */
+ execute(dname, ent->d_name);
+ }
+ closedir(dfd);
+ if( old_mode != -1 )
+ chmod(dname, old_mode);
+ }
+
+ if( cmd_tok&DO_ADIR )
+ {
+ lstat(dname, &cur_file_stat);
+ exec_for_item(1, dname);
+ }
+ return 0;
+}
+
+void exec_for_item(when, fname)
+int when; char * fname;
+{
+ int rv = -1;
+ switch(cmd_tok)
+ {
+ case CMD_FT: rv = cmd_ft(fname); break;
+
+ case CMD_CAT: rv = copy_file(fname, "-"); break;
+
+ case CMD_CHGRP: /* And fall */
+ case CMD_CHMOD: /* And fall */
+ case CMD_CHOWN: rv = copy_modes(fname); break;
+
+ case CMD_CP: rv = cmd_cp(fname); break;
+ case CMD_MV: rv = cmd_mv(fname); break;
+ case CMD_RM: rv = cmd_rm(fname); break;
+
+ case CMD_EXTAR: error(ENOSYS, "", ""); exit(1);
+
+ case CMD_LN+OK_DIR+OK_NO_SOURCE:
+ case CMD_LN: rv = cmd_ln(fname); break;
+
+ case CMD_INSTALL: error(EINVAL, "", "Bad program"); exit(1);
+
+ case CMD_MKDIR: rv = cmd_mkdir(fname); break;
+ case CMD_MKFIFO: rv = cmd_mkfifo(fname); break;
+#ifdef S_IFSOCK
+ case CMD_MKSOCK: rv = cmd_mksock(fname); break;
+#endif
+ case CMD_MKNOD: break;
+ }
+}
+
+void parse_perms(prefix, ustring)
+char * prefix; char * ustring;
+{
+ char * userstr;
+ char * groupstr;
+ char * modestr;
+ char * cp;
+ struct passwd * pwd = 0;
+ struct group * grp;
+
+ userstr = alloca(strlen(prefix) + strlen(ustring) + 2);
+ strcpy(userstr, prefix);
+ strcat(userstr, ustring);
+
+ /* Select User */
+ cp = strchr(userstr, ':');
+ if(!cp) cp = strchr(userstr, '.');
+ if(cp) *cp = '\0';
+
+ /* If there's a user */
+ if( *userstr != 0 )
+ {
+ pwd = getpwnam(userstr);
+ if(pwd == NULL)
+ {
+ if(!strisdigit(userstr) )
+ {
+ error(EINVAL, "Unknown user", userstr);
+ exit(1);
+ }
+ set_user = atoi(userstr);
+ }
+ else set_user = pwd->pw_uid;
+ endpwent();
+ }
+ if(cp)
+ {
+ groupstr = cp+1;
+ cp = strchr(groupstr, ':');
+ if(!cp) cp = strchr(groupstr, '.');
+ if(cp) *cp = '\0';
+ if( *groupstr != '\0' )
+ {
+ grp = getgrnam(groupstr);
+ if(grp == NULL)
+ {
+ if(!strisdigit(groupstr) )
+ {
+ error(EINVAL, "Unknown group", groupstr);
+ exit(1);
+ }
+ set_group = atoi(groupstr);
+ }
+ else set_group = grp->gr_gid;
+ endgrent();
+ }
+ else if( pwd )
+ set_group = pwd->pw_gid;
+ }
+ if(cp)
+ {
+ modestr = cp+1;
+ if(strisdigit(modestr))
+ set_mode = strtol(modestr, NULL, 8);
+ else
+ {
+ strncpy(mode_str, modestr, sizeof(mode_str)-1);
+ /* This is the time that the mode change will fail on syn error */
+ (void) edit_mode(u_mask, mode_str);
+ }
+ }
+
+ if( set_user < 0 && set_group < 0 && set_mode < 0 && *mode_str == 0)
+ {
+ error(EINVAL, "", "Permission string has no changes");
+ exit(1);
+ }
+}
+
+int edit_mode(mode, mode_str)
+int mode; char * mode_str;
+{
+ char * str=mode_str;
+static mtab[] = {0, 0111, 0222, 0333, 0444, 0555, 0666, 0777 };
+
+ int done_change = 0;
+ int isdir = S_ISDIR(mode);
+ int change_op = 0;
+ int change_mask = u_mask;
+ int v=0, s=0, nm=0;
+
+ for(; *mode_str; mode_str++)
+ {
+ switch(*mode_str)
+ {
+ case ',': change_op = 0;
+ change_mask=u_mask; continue;
+ case '=': change_op = 1; if(0) {
+ case '+': change_op = 2; } if(0) {
+ case '-': change_op = 3; }
+ v=0; nm=0;
+ if(strchr(",=+-", mode_str[1]) == 0 ) continue;
+ break;
+ case 'a': if(change_op) goto ch_error;
+ nm |= 07777; if(0) {
+ case 'u': nm |= 04700; s= 6; } if(0) {
+ case 'g': nm |= 02070; s= 3; } if(0) {
+ case 'o': nm |= 01007; s= 0; }
+ if(change_op==0) { change_mask=nm; continue; }
+ v |= mtab[(mode>>s)&7];
+ break;
+ case 'r': v |= 0444; break;
+ case 'w': v |= 0222; break;
+ case 'x': v |= 0111; break;
+ case 's': v |=06000; break;
+ case 't': v |=01000; break;
+ case 'X': v |= mtab[isdir]; break;
+ default: goto ch_error;
+ }
+ switch(change_op)
+ {
+ case 0: goto ch_error;
+ case 1: mode= ((mode&(~change_mask)) | (v&change_mask));
+ break;
+ case 2: mode= ( mode | (v&change_mask));
+ break;
+ case 3: mode= ( mode & ~(v&change_mask));
+ break;
+ }
+ done_change=1;
+ }
+ if(!done_change)
+ {
+ch_error:
+ error(EINVAL, "Invalid mode string", str);
+ exit(1);
+ }
+ return mode;
+}
+
+int
+cmd_ft(fname)
+char * fname;
+{
+static char oldpath[2048] = "~";
+static int last_uid=-1, last_gid=-1, last_mode=-1;
+ struct passwd * pptr;
+ struct group * gptr;
+
+ if( flg_verbose>1 )
+ {
+ char *p = 0;
+ if( fname[1] ) p = strrchr(fname, '/');
+ if( p )
+ {
+ *p = '\0';
+ if( strcmp(fname, oldpath) != 0 )
+ {
+ strcpy(oldpath, fname);
+ printf("%s/\n", oldpath);
+ }
+ *p = '/';
+ }
+ else if( *oldpath )
+ *oldpath = '\0';
+ if(p) printf("%s", p+1);
+ else printf("%s", fname);
+
+#ifdef S_IFLNK
+ if( S_ISLNK(cur_file_stat.st_mode))
+ {
+ char linkbuf[1024];
+ int v;
+ *linkbuf='\0';
+ v = readlink(fname, linkbuf, sizeof(linkbuf));
+ if(v>0) linkbuf[v] = '\0';
+ printf("\t+%s", linkbuf);
+ }
+ else
+#endif
+ if( cur_file_stat.st_mode != last_mode
+ || cur_file_stat.st_uid != last_uid
+ || cur_file_stat.st_gid != last_gid)
+ {
+ printf("\t");
+ if( cur_file_stat.st_uid != last_uid )
+ {
+ pptr = getpwuid(cur_file_stat.st_uid);
+ if( pptr )
+ printf("%s", pptr->pw_name);
+ else
+ printf("%d", cur_file_stat.st_uid);
+ }
+ printf(":");
+ if( cur_file_stat.st_gid != last_gid )
+ {
+ gptr = getgrgid(cur_file_stat.st_gid);
+ if( gptr )
+ printf("%s", gptr->gr_name);
+ else
+ printf("%d", cur_file_stat.st_gid);
+ }
+ if( (cur_file_stat.st_mode&07777) != (last_mode&07777) )
+ printf(":%03o", cur_file_stat.st_mode & 07777);
+
+ switch(cur_file_stat.st_mode & S_IFMT)
+ {
+ case S_IFDIR: printf("\td"); break;
+ case S_IFIFO: printf("\tp"); break;
+#ifdef S_IFSOCK
+ case S_IFSOCK: printf("\ts"); break;
+#endif
+ case S_IFBLK: printf("\tb,%d,%d", cur_file_stat.st_rdev>>8,
+ cur_file_stat.st_rdev&0xFF);
+ break;
+ case S_IFCHR: printf("\tc,%d,%d", cur_file_stat.st_rdev>>8,
+ cur_file_stat.st_rdev&0xFF);
+ break;
+ }
+ last_mode = ((cur_file_stat.st_mode&07777)|S_IFREG);
+ if( (cur_file_stat.st_mode&07000) ) last_mode = -1;
+ last_uid = cur_file_stat.st_uid;
+ last_gid = cur_file_stat.st_gid;
+ }
+ printf("\n");
+ }
+ else printf("%s\n", fname);
+
+ return 0;
+}
+
+int
+cmd_mkfifo(fname)
+char * fname;
+{
+ int rv;
+ int mode=0666;
+ if( set_mode >= 0 ) mode=set_mode;
+ rv = mknod(fname, S_IFIFO|mode, 0);
+ if(rv<0)
+ warning(errno, "Cannot create fifo", fname);
+ return rv;
+}
+
+#ifdef S_IFSOCK
+int
+cmd_mksock(fname)
+char * fname;
+{
+ int rv, fd, len;
+ struct sockaddr *adr;
+
+ len = strlen(fname)+1 + sizeof(*adr) - sizeof(adr->sa_data);
+ if( len < sizeof(*adr) ) len = sizeof(*adr);
+
+ adr = alloca(len+2);
+ adr->sa_family = AF_UNIX;
+ strcpy(adr->sa_data, fname);
+
+ rv = fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if( fd>=0 ) rv = bind(fd, adr, len);
+ if( fd>=0 ) close(fd);
+ if(set_mode >= 0 && chmod(fname, set_mode&07777) < 0 )
+ warning(errno, "Chmod", fname);
+
+ if(rv<0)
+ warning(errno, "Cannot create socket", fname);
+ return rv;
+}
+#endif
+
+int
+cmd_rm(fname)
+char * fname;
+{
+ struct stat dirstat;
+ int rv;
+ char * buf, * p;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ if( !flg_recurse ) return error(EISDIR, "", fname);
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ {
+ if( rmdir(fname) >= 0 ) return 0;
+ }
+ else
+ {
+ if( unlink(fname) >= 0 ) return 0;
+ }
+
+ if( !flg_force )
+ return error(errno, "", fname);
+
+ /* Try VERY hard */
+ buf = alloca(strlen(fname)+4);
+ strcpy(buf, fname);
+ p = strrchr(buf, '/');
+ if( p ) strcpy(p+1, "."); else strcpy(buf, ".");
+
+ if( stat(buf, &dirstat) < 0 ) return -1;
+ if( chmod(buf, dirstat.st_mode|0700) < 0 ) return -1;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ rv = rmdir(fname);
+ else
+ rv = unlink(fname);
+
+ chmod(buf, dirstat.st_mode);
+
+ return rv;
+}
+
+void
+build_dest(dest, name, newpath)
+char * dest; char * name; char * newpath;
+{
+ char * p;
+ strcpy(dest, newpath);
+ if( add_base )
+ {
+ strcat(dest, "/");
+ p = strrchr(or_name, '/');
+ if(p==0) strcat(dest, or_name);
+ else strcat(dest, p+1);
+ }
+ if(strlen(name) <= or_offset) return;
+ strcat(dest, name+or_offset);
+}
+
+int
+strisdigit(str)
+char * str;
+{
+ if( str==0 || *str == 0 ) return 0;
+
+ for(;*str; str++)
+ if(*str>'9'|| *str<'0') return 0;
+ return 1;
+}
+
+int
+cmd_mv(fname)
+char * fname;
+{
+ char * destfile;
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( !flg_force && lstat(destfile, &access_stat) == 0 )
+ return error(EEXIST, "", destfile);
+
+ if( rename(fname, destfile) == 0 ) return 0;
+
+ if( errno != EXDEV )
+ return error(errno, "", fname);
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ return error(EISDIR, "Can't rename across devices", fname);
+
+ if( copy_file(fname, destfile) != 0 ) return -1;
+ copy_modes(destfile);
+ return unlink(fname);
+}
+
+int
+cmd_ln(fname)
+char * fname;
+{
+ char * destfile;
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( lstat(destfile, &access_stat) != -1 )
+ {
+ if( !flg_force ) return error(EEXIST, "", destfile);
+ cmd_rm(destfile);
+ }
+
+#ifdef S_IFLNK
+ if( flg_symlink )
+ {
+ if( symlink(fname, destfile) == 0 ) return 0;
+ }
+ else
+ {
+#endif
+ if( link(fname, destfile) == 0 ) return 0;
+#ifdef S_IFLNK
+ }
+#endif
+
+ return error(errno, "", destfile);
+}
+
+int
+cmd_cp(fname)
+char * fname;
+{
+ struct stat dest_stat;
+ char * destfile;
+ int no_dest = 0;
+
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( stat(destfile, &dest_stat) >= 0 )
+ {
+ if( dest_stat.st_ino == cur_file_stat.st_ino
+ && dest_stat.st_dev == cur_file_stat.st_dev )
+ {
+ warning(EPERM, "Can't copy file to itself", fname);
+ return -1;
+ }
+ }
+ else no_dest = 1;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ {
+ if( !no_dest )
+ {
+ if( S_ISDIR(dest_stat.st_mode) ) return 0;
+ if( unlink(destfile) < 0 )
+ return error(errno, "Can't delete", destfile);
+ }
+ return cmd_mkdir(destfile);
+ }
+ else if( S_ISDIR(dest_stat.st_mode) )
+ return error(EPERM, "Can't copy non-directory to directory", destfile);
+ else if( S_ISREG(cur_file_stat.st_mode) )
+ {
+ /* Copy_ok - do we want to force a real file */;
+ if( flg_force && !no_dest && !S_ISREG(dest_stat.st_mode) )
+ cmd_rm(destfile);
+ }
+ else if( flg_recurse ) /* Don't copy other things while recursing */
+ {
+ return error(EPERM, "Can't copy", fname);
+ }
+
+ if( copy_file(fname, destfile) != 0 ) return -1;
+ if( flg_preserve ) copy_modes(destfile);
+ return 0;
+}
+
+int
+copy_modes(file)
+char * file;
+{
+ int user, group, mode;
+ /* chown turns off set[ug]id bits for non-root,
+ so do the chmod last. */
+
+ /* Try to copy the old file's modtime and access time. */
+ if(set_time)
+ {
+ struct utimbuf tv;
+
+ tv.actime = cur_file_stat.st_atime;
+ tv.modtime = cur_file_stat.st_mtime;
+ if( set_time != -1 )
+ tv.modtime = set_time;
+ if (utime (file, &tv) && !flg_force)
+ return error (errno, "", file);
+ }
+
+ /* Try to preserve ownership. For non-root it might fail, but that's ok.
+ But root probably wants to know, e.g. if NFS disallows it. */
+ user = cur_file_stat.st_uid; if(set_user>=0) user = set_user;
+ group = cur_file_stat.st_gid; if(set_group>=0) group = set_group;
+
+ if (chown (file, user, group)
+ && (errno != EPERM || geteuid() == 0 || (flg_preserve==0 && flg_force==0)))
+ error (errno, "Can't change perms for", file);
+
+ mode = cur_file_stat.st_mode;
+ if(set_mode>=0) mode=set_mode;
+ else if(*mode_str)
+ mode = edit_mode(mode, mode_str);
+
+ if (chmod (file, mode & 07777))
+ return error (errno, "", file);
+
+ return 0;
+}
+
+/* This copies from something to a file or stdout */
+/* If the source has zero blocks (possibly holes) the destination
+ * is built with holes (assuming it's a normal file) */
+
+int
+copy_file(source, dest)
+char * source; char * dest;
+{
+ char * buf;
+ int sfd, dfd;
+ struct stat st;
+ int blksz = BUFSIZ;
+ int cc;
+ char * ptr;
+ int hole_flag = 0;
+ int retv = 0;
+ int no_seek;
+ int mmode = 0666;
+
+ if(flg_verbose>1) printf("%s -> %s\n", source, dest);
+ if( strcmp(source, "-") == 0 )
+ sfd = 0;
+ else
+ {
+ sfd = open(source, O_RDONLY);
+ if(sfd<0) return error(errno, "", source);
+ mmode = (cur_file_stat.st_mode&0777);
+ }
+
+ if( strcmp(dest, "-") == 0 )
+ dfd = 1;
+ else
+ {
+ dfd = open(dest, O_WRONLY|O_TRUNC|O_CREAT, mmode);
+ if(dfd<0)
+ {
+ close(sfd);
+ return error(errno, "Cannot create", source);
+ }
+ }
+
+ if( fstat(dfd, &st) )
+ {
+ retv = error(errno, "", dest);
+ no_seek = 1;
+ }
+ else
+ {
+#ifndef __BCC__
+ blksz = st.st_blksize;
+#endif
+ no_seek = !S_ISREG(st.st_mode);
+ }
+ buf = alloca(blksz + sizeof(int));
+ if( buf == 0 ) return error(0, "Out of memory", "");
+
+ for(;;)
+ {
+ cc = read(sfd, buf, blksz);
+ if(cc<0)
+ {
+ retv = error(errno, "", source);
+ goto exit_now;
+ }
+ if(cc==0) break;
+ buf[cc] = 1;
+ for(ptr=buf; *ptr==0 ; ptr++) ;
+ if((hole_flag = (ptr == buf+cc)))
+ { /* Make a hole */
+ if( lseek(dfd, (off_t) cc, SEEK_CUR) < 0 )
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+ else
+ {
+ if( cc != write(dfd, buf, cc))
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+ }
+ if( hole_flag )
+ {
+ if( lseek(dfd, (off_t) -1, SEEK_CUR) < 0
+ || write(dfd, "", 1) != 1 )
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+
+exit_now:
+ if(sfd>2) close(sfd);
+ if(dfd>2) close(dfd);
+ return retv;
+}
+
+void
+Usage()
+{
+ int i;
+
+ printf("FileTool Usage: %s%s", prog_name[0]=='-'?"ft -":"", prog_name);
+ if( cmd_tok == CMD_FT )
+ {
+ printf(" --[com_name] [-options] [files]\n");
+ printf("\nAvailable commands are:\n");
+ }
+
+ for(i=1; command_list[i].name; i++)
+ {
+ if( cmd_tok == CMD_FT )
+ printf(" %s --%s", prog_name, command_list[i].name);
+ else if( cmd_tok != command_list[i].cmd )
+ continue;
+
+ if( *command_list[i].opts )
+ printf(" [-%s]", command_list[i].opts);
+ switch(command_list[i].argpat)
+ {
+ case 1: printf(" <info> [files]"); break;
+ case -1: printf(" [files] [dest]"); break;
+ case 0: printf(" [files]"); break;
+ default: printf(" path [bcu] major minor"); break;
+ }
+ printf("\n");
+ }
+
+ exit(99);
+}
+
+int
+cmd_mkdir(dirname)
+char * dirname;
+{
+ int retv;
+ int mode = 0777;
+ if( set_mode >= 0 ) mode = set_mode;
+
+ retv = mkdir(dirname, mode);
+ if(retv<0)
+ {
+ if(flg_mkpdir && errno == ENOENT)
+ {
+ /* Create parents */
+ }
+ }
+ if( retv>=0 && cmd_tok == CMD_MKDIR )
+ {
+ if( set_user > 0 || set_group > 0 )
+ {
+ if( chown(dirname, set_user, set_group) < 0)
+ warning(errno, "Cannot change directory owner", dirname);
+ else if( chmod (dirname, mode & 07777) )
+ warning(errno, "", dirname);
+ }
+ }
+
+ if(retv<0) error(errno, "Cannot create directory", dirname);
+ return retv;
+}
+
+int
+cmd_mknod()
+{
+ int device;
+ int rv = -1;
+ int mode=0666;
+ if( set_mode >= 0 ) mode=set_mode;
+
+ device = (atoi(flist[2])<<8) + atoi(flist[3]);
+
+ if(flist[1][0] == 'b')
+ rv = mknod(flist[0], S_IFBLK|mode, device);
+ else if(flist[1][0] == 'c' || flist[1][0] == 'u')
+ rv = mknod(flist[0], S_IFCHR|mode, device);
+ else Usage();
+
+ if(rv<0)
+ {
+ error(errno, "", flist[0]);
+ exit(1);
+ }
+ return rv;
+}
+
+int
+warn_func(enumber, estr, eobj)
+int enumber; char * estr; char * eobj;
+{
+ if(flg_verbose)
+ return error_func(enumber, estr, eobj);
+ return 0;
+}
+
+int
+error_func(enumber, estr, eobj)
+int enumber; char * estr; char * eobj;
+{
+ fprintf(stderr, "%s%s(%d): ", prog_name[0]=='-'?"ft":"", prog_name, Line_no);
+ fprintf(stderr, "%s%s%s: %s\n", estr, (*estr?" ":""), eobj, strerror(enumber));
+ return -1;
+}