int main (void) { char buf[80]; int result; /* Remove any leftovers from a previous partial run. */ ignore_value (system ("rm -rf " BASE "*")); /* Perform same checks as counterpart functions. */ result = test_readlink (do_readlink, false); dfd = openat (AT_FDCWD, ".", O_RDONLY); ASSERT (0 <= dfd); ASSERT (test_readlink (do_readlink, false) == result); /* Now perform some cross-directory checks. Skip everything else on mingw. */ if (HAVE_SYMLINK) { const char *contents = "don't matter!"; ssize_t exp = strlen (contents); /* Create link while cwd is '.', then read it in '..'. */ ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == 0); errno = 0; ASSERT (symlinkat (contents, dfd, BASE "link") == -1); ASSERT (errno == EEXIST); ASSERT (chdir ("..") == 0); errno = 0; ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == -1); ASSERT (errno == ENOENT); ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); ASSERT (unlinkat (dfd, BASE "link", 0) == 0); /* Create link while cwd is '..', then read it in '.'. */ ASSERT (symlinkat (contents, dfd, BASE "link") == 0); ASSERT (fchdir (dfd) == 0); errno = 0; ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == -1); ASSERT (errno == EEXIST); buf[0] = '\0'; ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); buf[0] = '\0'; ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); ASSERT (unlink (BASE "link") == 0); } ASSERT (close (dfd) == 0); if (result == 77) fputs ("skipping test: symlinks not supported on this file system\n", stderr); return result; }
CAMLprim value caml_extunix_symlinkat(value v_path, value v_newdirfd, value v_newname) { CAMLparam3(v_path, v_newdirfd, v_newname); int ret = symlinkat(String_val(v_path), Int_val(v_newdirfd), String_val(v_newname)); if (ret != 0) uerror("symlinkat", v_path); CAMLreturn(Val_unit); }
int open_image_dir(char *dir) { int fd, ret; fd = open(dir, O_RDONLY); if (fd < 0) { pr_perror("Can't open dir %s", dir); return -1; } ret = install_service_fd(IMG_FD_OFF, fd); close(fd); fd = ret; if (opts.img_parent) { ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK); if (ret < 0 && errno != EEXIST) { pr_perror("Can't link parent snapshot"); goto err; } if (opts.img_parent[0] == '/') pr_warn("Absolute paths for parent links " "may not work on restore!\n"); } return 0; err: close_image_dir(); return -1; }
int open_image_dir(char *dir) { int fd, ret; fd = open(dir, O_RDONLY); if (fd < 0) { pr_perror("Can't open dir %s", dir); return -1; } ret = install_service_fd(IMG_FD_OFF, fd); close(fd); fd = ret; if (opts.img_parent) { ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK); if (ret < 0 && errno != EEXIST) { pr_perror("Can't link parent snapshot"); goto err; } } return 0; err: close_image_dir(); return -1; }
int ast_symlinkat(const char* path, int cwd, const char* linkpath) { int r = -1; PATHIFY(cwd, path, 1, 1); RESTART(r, symlinkat(path, cwd, linkpath)); PATHEND(); return r; }
static int copyat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) { int err; int oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NOATIME); if (oldfd == -1 && errno == EPERM) { oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); } if (oldfd == -1 && errno == ELOOP) { char oldtarget[PATH_MAX]; ssize_t oldlen = readlinkat(olddirfd, oldpath, oldtarget, sizeof(oldtarget)); if (oldlen == -1) { return -1; } oldtarget[oldlen] = '\0'; return symlinkat(oldtarget, newdirfd, newpath); } if (oldfd == -1) { return -1; } struct stat oldstat; if (fstat(oldfd, &oldstat) == -1) { err = errno; close(oldfd); errno = err; return -1; } int newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC | O_NOATIME, oldstat.st_mode); if (newfd == -1 && errno == EPERM) { newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, oldstat.st_mode); } if (newfd == -1) { err = errno; close(oldfd); errno = err; return -1; } if (fchown(newfd, oldstat.st_uid, oldstat.st_gid) == -1) { // ignore error } if (copyfile_sparse(oldfd, newfd) == -1) { err = errno; close(newfd); close(oldfd); errno = err; return -1; } close(newfd); close(oldfd); struct timespec times[2]; times[0] = oldstat.st_atim; times[1] = oldstat.st_mtim; utimensat(newdirfd, newpath, times, 0); // ignore error return 0; }
CAMLprim value netsys_symlinkat(value oldpath, value newdirfd, value newpath) { #ifdef HAVE_AT if (symlinkat(String_val(oldpath), Int_val(newdirfd), String_val(newpath)) == -1) uerror("symlinkat", oldpath); return Val_unit; #else invalid_argument("Netsys_posix.symlinkat not available"); #endif }
/* Create a symlink, but reject trailing slash. */ int rpl_symlinkat (char const *contents, int fd, char const *name) { size_t len = strlen (name); if (len && name[len - 1] == '/') { struct stat st; if (fstatat (fd, name, &st, 0) == 0) errno = EEXIST; return -1; } return symlinkat (contents, fd, name); }
int main() { struct stat st; struct stat st2; openat(AT_FDCWD, PWD "openat.txt", O_CREAT | O_WRONLY, 0644); assert(stat("openat.txt", &st) == 0); // relative path assert(faccessat(AT_FDCWD, PWD "openat.txt", F_OK, 0) == 0); assert(fstatat(AT_FDCWD, PWD "openat.txt", &st2, 0) == 0); assert(fchmodat(AT_FDCWD, PWD "openat.txt", 0777, 0) == 0); struct timeval my_times[2]; my_times[0].tv_sec = 0; my_times[0].tv_usec = 0; my_times[1].tv_sec = 0; my_times[1].tv_usec = 0; assert(futimesat(AT_FDCWD, PWD "openat.txt", my_times, 0) == 0); // see /etc/passwd, user 'pgbovine' is 508:100 assert(fchownat(AT_FDCWD, PWD "openat.txt", 508, 100, 0) == 0); assert(linkat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_hardlink.txt", 0) == 0); assert(stat("openat_hardlink.txt", &st) == 0); // relative path assert(symlinkat(PWD "openat.txt", AT_FDCWD, PWD "openat_symlink.txt") == 0); assert(lstat("openat_symlink.txt", &st) == 0); // relative path char res[300]; assert(readlinkat(AT_FDCWD, PWD "openat_symlink.txt", res, sizeof(res)) > 0); assert(renameat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_newname.txt", 0) == 0); assert(stat("openat.txt", &st) != 0); // should not exist anymore assert(stat("openat_newname.txt", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "openat_newname.txt", 0); unlinkat(AT_FDCWD, PWD "openat_hardlink.txt", 0); unlinkat(AT_FDCWD, PWD "openat_symlink.txt", 0); mknodat(AT_FDCWD, PWD "mknodat.fifo", S_IFIFO); assert(stat("mknodat.fifo", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "mknodat.fifo", 0); mkdirat(AT_FDCWD, PWD "mkdirat_dir", 0); assert(stat("mkdirat_dir", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "mkdirat_dir", AT_REMOVEDIR); // like 'rmdir' return 0; }
void compile_database(repo_t *repo, file_t *db, int contents) { db_writer_t *writer = db_writer_new(repo, db); alpm_list_t *pkg, *pkgs = repo->pkgcache->list; for (pkg = pkgs; pkg; pkg = pkg->next) { alpm_pkg_meta_t *metadata = pkg->data; compile_database_entry(repo, writer, metadata, contents); } db_writer_close(writer); /* make the appropriate symlink for the database */ if (symlinkat(db->file, repo->dirfd, db->link_file) < 0 && errno != EEXIST) err(EXIT_FAILURE, "symlink for %s failed", db->link_file); }
static int callback_symlink (const char *from, const char *to) { struct stat stbuf; to = ENSURE_RELPATH (to); if (symlinkat (from, basefd, to) == -1) return -errno; if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) { fprintf (stderr, "Failed to find newly created symlink '%s': %s\n", to, g_strerror (errno)); exit (EXIT_FAILURE); } return 0; }
void sign_database(repo_t *repo, file_t *db, const char *key) { int dbfd = openat(repo->dirfd, db->file, O_RDONLY); if (dbfd < 0) err(EXIT_FAILURE, "failed to open %s", db->file); int sigfd = openat(repo->dirfd, db->sig, O_CREAT | O_WRONLY | O_TRUNC, 0644); if (sigfd < 0) err(EXIT_FAILURE, "failed to open %s for writing", db->sig); /* XXX: check return type */ gpgme_sign(dbfd, sigfd, key); close(sigfd); close(dbfd); if (symlinkat(db->sig, repo->dirfd, db->link_sig) < 0 && errno != EEXIST) err(EXIT_FAILURE, "symlink for %s failed", db->link_sig); }
void test_create_symlink_at() { char *symlink_filename = alloc_filename("symlink"); int dir_fd = get_dir_fd("."); const char *dest_path = "dest_path"; t_check_zero(symlinkat(dest_path, dir_fd, symlink_filename)); char buf[100]; int got; got = readlinkat(dir_fd, symlink_filename, buf, sizeof(buf)); t_check(got >= 0); assert(got == strlen(dest_path)); buf[got] = 0; assert(strcmp(buf, dest_path) == 0); t_check_zero(unlinkat(dir_fd, symlink_filename, 0)); close(dir_fd); free(symlink_filename); }
/* * Like symlinkat() but overwrites (atomically) an existing * symlink. */ static gboolean symlink_at_replace (const char *oldpath, int parent_dfd, const char *newpath, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int res; /* Possibly in the future generate a temporary random name here, * would need to move "generate a temporary name" code into * libglnx or glib? */ const char *temppath = glnx_strjoina (newpath, ".tmp"); /* Clean up any stale temporary links */ (void) unlinkat (parent_dfd, temppath, 0); /* Create the temp link */ do res = symlinkat (oldpath, parent_dfd, temppath); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (res == -1) { glnx_set_error_from_errno (error); goto out; } /* Rename it into place */ do res = renameat (parent_dfd, temppath, parent_dfd, newpath); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (res == -1) { glnx_set_error_from_errno (error); goto out; } ret = TRUE; out: return ret; }
static int link_file(int dirfd, const char *filename, int type, unsigned long hash, unsigned char *digest) { char linkfn[32]; int id; id = get_link_id(type, hash, digest); if (id < 0) { fprintf(stderr, "WARNING: Skipping duplicate certificate in file %s\n", filename); return -1; } snprintf(linkfn, sizeof(linkfn), "%08lx.%s%d", hash, prefixes[type], id); fprintf(stdout, "%s => %s\n", linkfn, filename); if (symlinkat(filename, dirfd, linkfn) < 0) perror(linkfn); return 0; }
static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) { _cleanup_free_ char *target = NULL; int r; assert(from); assert(st); assert(to); r = readlinkat_malloc(df, from, &target); if (r < 0) return r; if (symlinkat(target, dt, to) < 0) return -errno; if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0) return -errno; return 0; }
int main(int argc, char *argv[]) { int fd; if (!mkdtemp(dir)) err(2, "mkdtemp"); err_set_exit(cleanup); fd = open(dir, O_DIRECTORY | O_RDONLY); if (fd == -1) err(2, "open %s", dir); if (mkdirat(fd, "d1", 0777) == -1) err(2, "mkdirat d1"); if (symlinkat(dir, fd, "d1/looper") == -1) err(2, "symlinkat looper"); ftwflags = FTW_PHYS; if (nftw(dir, cb, 10, ftwflags) == -1) err(2, "nftw FTW_PHYS"); ftwflags = FTW_PHYS | FTW_DEPTH; if (nftw(dir, cb, 10, ftwflags) == -1) err(2, "nftw FTW_PHYS | FTW_DEPTH"); ftwflags = 0; if (nftw(dir, cb, 10, ftwflags) == -1) err(2, "nftw 0"); ftwflags = FTW_DEPTH; if (nftw(dir, cb, 10, ftwflags) == -1) err(2, "nftw FTW_DEPTH"); close(fd); printf("PASS nftw()\n"); cleanup(failures != 0); return (failures != 0); }
int open_image_dir(char *dir) { int fd, ret; fd = open(dir, O_RDONLY); if (fd < 0) { pr_perror("Can't open dir %s", dir); return -1; } ret = install_service_fd(IMG_FD_OFF, fd); if (opts.img_parent) { int pfd; ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK); if (ret < 0) { pr_perror("Can't link parent snapshot."); goto err; } pfd = openat(fd, CR_PARENT_LINK, O_RDONLY); if (pfd < 0) { pr_perror("Can't open parent snapshot."); goto err; } ret = install_service_fd(PARENT_FD_OFF, pfd); close(pfd); } close(fd); return ret; err: close_image_dir(); return -1; }
string writeScript(const string& ckptDir, bool uniqueCkptFilenames, const time_t& ckptTimeStamp, const uint32_t theCheckpointInterval, const int thePort, const UniquePid& compId, const map<string, vector<string> >& restartFilenames) { ostringstream o; string uniqueFilename; o << string(ckptDir) << "/" << RESTART_SCRIPT_BASENAME << "_" << compId; if (uniqueCkptFilenames) { o << "_" << std::setw(5) << std::setfill('0') << compId.computationGeneration(); } o << "." << RESTART_SCRIPT_EXT; uniqueFilename = o.str(); const bool isSingleHost = (restartFilenames.size() == 1); map< string, vector<string> >::const_iterator host; size_t numPeers; for (host = restartFilenames.begin(); host != restartFilenames.end(); host++) { numPeers += host->second.size(); } vector<string>::const_iterator file; char hostname[80]; char timestamp[80]; gethostname ( hostname, 80 ); JTRACE ( "writing restart script" ) ( uniqueFilename ); FILE* fp = fopen ( uniqueFilename.c_str(),"w" ); JASSERT ( fp!=0 )(JASSERT_ERRNO)( uniqueFilename ) .Text ( "failed to open file" ); fprintf ( fp, "%s", header ); fprintf ( fp, "%s", checkLocal ); fprintf ( fp, "%s", slurmHelperContactFunction ); fprintf ( fp, "%s", usage ); ctime_r(&ckptTimeStamp, timestamp); // Remove the trailing '\n' timestamp[strlen(timestamp) - 1] = '\0'; fprintf ( fp, "ckpt_timestamp=\"%s\"\n\n", timestamp ); fprintf ( fp, "coord_host=$" ENV_VAR_NAME_HOST "\n" "if test -z \"$" ENV_VAR_NAME_HOST "\"; then\n" " coord_host=%s\nfi\n\n" "coord_port=$" ENV_VAR_NAME_PORT "\n" "if test -z \"$" ENV_VAR_NAME_PORT "\"; then\n" " coord_port=%d\nfi\n\n" "checkpoint_interval=$" ENV_VAR_CKPT_INTR "\n" "if test -z \"$" ENV_VAR_CKPT_INTR "\"; then\n" " checkpoint_interval=%d\nfi\n" "export DMTCP_CHECKPOINT_INTERVAL=${checkpoint_interval}\n\n", hostname, thePort, theCheckpointInterval ); fprintf ( fp, "%s", cmdlineArgHandler ); fprintf ( fp, "dmt_rstr_cmd=%s/" DMTCP_RESTART_CMD "\n" "which $dmt_rstr_cmd > /dev/null 2>&1" " || dmt_rstr_cmd=" DMTCP_RESTART_CMD "\n" "which $dmt_rstr_cmd > /dev/null 2>&1" " || echo \"$0: $dmt_rstr_cmd not found\"\n" "which $dmt_rstr_cmd > /dev/null 2>&1 || exit 1\n\n", jalib::Filesystem::GetProgramDir().c_str()); fprintf ( fp, "# Number of hosts in the computation = %zu\n" "# Number of processes in the computation = %zu\n\n", restartFilenames.size(), numPeers ); if ( isSingleHost ) { JTRACE ( "Single HOST" ); host=restartFilenames.begin(); ostringstream o; for ( file=host->second.begin(); file!=host->second.end(); ++file ) { o << " " << *file; } fprintf ( fp, "given_ckpt_files=\"%s\"\n\n", o.str().c_str()); fprintf ( fp, "%s", singleHostProcessing ); } else { fprintf ( fp, "%s", "# SYNTAX:\n" "# :: <HOST> :<MODE>: <CHECKPOINT_IMAGE> ...\n" "# Host names and filenames must not include \':\'\n" "# At most one fg (foreground) mode allowed; it must be last.\n" "# \'maybexterm\' and \'maybebg\' are set from <MODE>.\n"); fprintf ( fp, "%s", "worker_ckpts=\'" ); for ( host=restartFilenames.begin(); host!=restartFilenames.end(); ++host ) { fprintf ( fp, "\n :: %s :bg:", host->first.c_str() ); for ( file=host->second.begin(); file!=host->second.end(); ++file ) { fprintf ( fp," %s", file->c_str() ); } } fprintf ( fp, "%s", "\n\'\n\n" ); fprintf( fp, "# Check for resource manager\n" "ibrun_path=$(which ibrun 2> /dev/null)\n" "if [ ! -n \"$ibrun_path\" ]; then\n" " discover_rm_path=$(which dmtcp_discover_rm)\n" " if [ -n \"$discover_rm_path\" ]; then\n" " eval $(dmtcp_discover_rm -t)\n" " srun_path=$(which srun 2> /dev/null)\n" " llaunch=`which dmtcp_rm_loclaunch`\n" " if [ $RES_MANAGER = \"SLURM\" ] && [ -n \"$srun_path\" ]; then\n" " eval $(dmtcp_discover_rm -n \"$worker_ckpts\")\n" " if [ -n \"$DMTCP_DISCOVER_RM_ERROR\" ]; then\n" " echo \"Restart error: $DMTCP_DISCOVER_RM_ERROR\"\n" " echo \"Allocated resources: $manager_resources\"\n" " exit 0\n" " fi\n" " export DMTCP_REMLAUNCH_NODES=$DMTCP_REMLAUNCH_NODES\n" " bound=$(($DMTCP_REMLAUNCH_NODES - 1))\n" " for i in $(seq 0 $bound); do\n" " eval \"val=\\${DMTCP_REMLAUNCH_${i}_SLOTS}\"\n" " export DMTCP_REMLAUNCH_${i}_SLOTS=\"$val\"\n" " bound2=$(($val - 1))\n" " for j in $(seq 0 $bound2); do\n" " eval \"ckpts=\\${DMTCP_REMLAUNCH_${i}_${j}}\"\n" " export DMTCP_REMLAUNCH_${i}_${j}=\"$ckpts\"\n" " done\n" " done\n" " if [ \"$DMTCP_DISCOVER_PM_TYPE\" = \"HYDRA\" ]; then\n" " export DMTCP_SRUN_HELPER_SYNCFILE=`mktemp ./tmp.XXXXXXXXXX`\n" " rm $DMTCP_SRUN_HELPER_SYNCFILE\n" " dmtcp_srun_helper -r $srun_path \"$llaunch\"\n" " if [ ! -f $DMTCP_SRUN_HELPER_SYNCFILE ]; then\n" " echo \"Error launching application\"\n" " exit 1\n" " fi\n" " # export helper contact info\n" " . $DMTCP_SRUN_HELPER_SYNCFILE\n" " pass_slurm_helper_contact \"$DMTCP_LAUNCH_CKPTS\"\n" " rm $DMTCP_SRUN_HELPER_SYNCFILE\n" " dmtcp_restart --join --coord-host $DMTCP_COORD_HOST" " --coord-port $DMTCP_COORD_PORT" " $DMTCP_LAUNCH_CKPTS\n" " else\n" " DMTCP_REMLAUNCH_0_0=\"$DMTCP_REMLAUNCH_0_0" " $DMTCP_LAUNCH_CKPTS\"\n" " $srun_path \"$llaunch\"\n" " fi\n" " exit 0\n" " elif [ $RES_MANAGER = \"TORQUE\" ]; then\n" " #eval $(dmtcp_discover_rm \"$worker_ckpts\")\n" " #if [ -n \"$new_worker_ckpts\" ]; then\n" " # worker_ckpts=\"$new_worker_ckpts\"\n" " #fi\n" " eval $(dmtcp_discover_rm -n \"$worker_ckpts\")\n" " if [ -n \"$DMTCP_DISCOVER_RM_ERROR\" ]; then\n" " echo \"Restart error: $DMTCP_DISCOVER_RM_ERROR\"\n" " echo \"Allocated resources: $manager_resources\"\n" " exit 0\n" " fi\n" " arguments=\"PATH=$PATH DMTCP_COORD_HOST=$DMTCP_COORD_HOST" " DMTCP_COORD_PORT=$DMTCP_COORD_PORT\"\n" " arguments=$arguments\" DMTCP_CHECKPOINT_INTERVAL=$DMTCP_CHECKPOINT_INTERVAL\"\n" " arguments=$arguments\" DMTCP_TMPDIR=$DMTCP_TMPDIR\"\n" " arguments=$arguments\" DMTCP_REMLAUNCH_NODES=$DMTCP_REMLAUNCH_NODES\"\n" " bound=$(($DMTCP_REMLAUNCH_NODES - 1))\n" " for i in $(seq 0 $bound); do\n" " eval \"val=\\${DMTCP_REMLAUNCH_${i}_SLOTS}\"\n" " arguments=$arguments\" DMTCP_REMLAUNCH_${i}_SLOTS=\\\"$val\\\"\"\n" " bound2=$(($val - 1))\n" " for j in $(seq 0 $bound2); do\n" " eval \"ckpts=\\${DMTCP_REMLAUNCH_${i}_${j}}\"\n" " arguments=$arguments\" DMTCP_REMLAUNCH_${i}_${j}=\\\"$ckpts\\\"\"\n" " done\n" " done\n" " pbsdsh -u \"$llaunch\" \"$arguments\"\n" " exit 0\n" " fi\n" " fi\n" "fi\n" "\n\n" ); fprintf ( fp, "%s", multiHostProcessing ); } fclose ( fp ); { string filename = RESTART_SCRIPT_BASENAME "." RESTART_SCRIPT_EXT; string dirname = jalib::Filesystem::DirName(uniqueFilename); int dirfd = open(dirname.c_str(), O_DIRECTORY | O_RDONLY); JASSERT(dirfd != -1) (dirname) (JASSERT_ERRNO); /* Set execute permission for user. */ struct stat buf; JASSERT(::stat(uniqueFilename.c_str(), &buf) == 0); JASSERT(chmod(uniqueFilename.c_str(), buf.st_mode | S_IXUSR) == 0); // Create a symlink from // dmtcp_restart_script.sh -> dmtcp_restart_script_<curCompId>.sh unlink(filename.c_str()); JTRACE("linking \"dmtcp_restart_script.sh\" filename to uniqueFilename") (filename) (dirname) (uniqueFilename); // FIXME: Handle error case of symlink() JWARNING(symlinkat(basename(uniqueFilename.c_str()), dirfd, filename.c_str()) == 0) (JASSERT_ERRNO); JASSERT(close(dirfd) == 0); } return uniqueFilename; }
int q_main(int argc, char **argv) { int i, install; const char *p; APPLET func; if (argc == 0) return 1; argv0 = p = basename(argv[0]); if ((func = lookup_applet(p)) == NULL) return 1; if (strcmp("q", p) != 0) return (func)(argc, argv); if (argc == 1) q_usage(EXIT_FAILURE); install = 0; while ((i = GETOPT_LONG(Q, q, "+")) != -1) { switch (i) { COMMON_GETOPTS_CASES(q) case 'M': modpath = optarg; break; case 'i': install = 1; break; } } if (install) { char buf[_Q_PATH_MAX]; const char *prog, *dir; ssize_t rret; int fd, ret; if (!quiet) printf("Installing symlinks:\n"); #if defined(__MACH__) rret = proc_pidpath(getpid(), buf, sizeof(buf)); if (rret != -1) rret = strlen(buf); #elif defined(__sun) && defined(__SVR4) prog = getexecname(); rret = strlen(prog); if ((size_t)rret > sizeof(buf) - 1) { rret = -1; } else { snprintf(buf, sizeof(buf), "%s", prog); } #else rret = readlink("/proc/self/exe", buf, sizeof(buf) - 1); #endif if (rret == -1) { warnfp("haha no symlink love for you"); return 1; } buf[rret] = '\0'; prog = basename(buf); dir = dirname(buf); fd = open(dir, O_RDONLY|O_CLOEXEC|O_PATH); if (fd < 0) { warnfp("open(%s) failed", dir); return 1; } ret = 0; for (i = 1; applets[i].desc; ++i) { int r = symlinkat(prog, fd, applets[i].name); if (!quiet) printf(" %s ...\t[%s]\n", applets[i].name, r ? strerror(errno) : "OK"); if (r && errno != EEXIST) ret = 1; } close(fd); return ret; } if (argc == optind) q_usage(EXIT_FAILURE); if ((func = lookup_applet(argv[optind])) == NULL) return 1; /* In case of "q --option ... appletname ...", remove appletname from the * applet's args. */ if (optind > 1) { argv[0] = argv[optind]; for (i = optind; i < argc; ++i) argv[i] = argv[i + 1]; } else ++argv; optind = 0; /* reset so the applets can call getopt */ return (func)(argc - 1, argv); }
/* * Given a file descriptor, create a capability with specific rights and * make sure only those rights work. */ static int try_file_ops(int filefd, int dirfd, cap_rights_t rights) { struct stat sb; struct statfs sf; cap_rights_t erights; int fd_cap, fd_capcap, dfd_cap; ssize_t ssize, ssize2; off_t off; void *p; char ch; int ret, is_nfs; struct pollfd pollfd; int success = -1; REQUIRE(fstatfs(filefd, &sf)); is_nfs = (strcmp("nfs", sf.f_fstypename) == 0); REQUIRE(fd_cap = cap_new(filefd, rights)); CHECK(cap_getrights(fd_cap, &erights) == 0); CHECK(rights == erights); REQUIRE(fd_capcap = cap_new(fd_cap, rights)); CHECK(cap_getrights(fd_capcap, &erights) == 0); CHECK(rights == erights); CHECK(fd_capcap != fd_cap); REQUIRE(dfd_cap = cap_new(dirfd, rights)); CHECK(cap_getrights(dfd_cap, &erights) == 0); CHECK(rights == erights); ssize = read(fd_cap, &ch, sizeof(ch)); CHECK_RESULT(read, CAP_READ, ssize >= 0); ssize = write(fd_cap, &ch, sizeof(ch)); CHECK_RESULT(write, CAP_WRITE, ssize >= 0); off = lseek(fd_cap, 0, SEEK_SET); CHECK_RESULT(lseek, CAP_SEEK, off >= 0); ssize = pread(fd_cap, &ch, sizeof(ch), 0); ssize2 = pread(fd_cap, &ch, sizeof(ch), 0); CHECK_RESULT(pread, CAP_PREAD, ssize >= 0); CHECK(ssize == ssize2); ssize = pwrite(fd_cap, &ch, sizeof(ch), 0); CHECK_RESULT(pwrite, CAP_PWRITE, ssize >= 0); p = mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP); p = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_R); p = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_W); p = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_X); p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_RW); p = mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_RX); p = mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_WX); p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd_cap, 0); CHECK_MMAP_RESULT(CAP_MMAP_RWX); ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDONLY, 0600); CHECK_RESULT(openat(O_CREATE | O_RDONLY), CAP_CREATE | CAP_READ | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0); ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY | O_APPEND, 0600); CHECK_RESULT(openat(O_CREATE | O_WRONLY | O_APPEND), CAP_CREATE | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0); ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR | O_APPEND, 0600); CHECK_RESULT(openat(O_CREATE | O_RDWR | O_APPEND), CAP_CREATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0); ret = fsync(fd_cap); CHECK_RESULT(fsync, CAP_FSYNC, ret == 0); ret = openat(dirfd, "cap_fsync", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDONLY); CHECK_RESULT(openat(O_FSYNC | O_RDONLY), CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY | O_APPEND); CHECK_RESULT(openat(O_FSYNC | O_WRONLY | O_APPEND), CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR | O_APPEND); CHECK_RESULT(openat(O_FSYNC | O_RDWR | O_APPEND), CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDONLY); CHECK_RESULT(openat(O_SYNC | O_RDONLY), CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY | O_APPEND); CHECK_RESULT(openat(O_SYNC | O_WRONLY | O_APPEND), CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR | O_APPEND); CHECK_RESULT(openat(O_SYNC | O_RDWR | O_APPEND), CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0); ret = ftruncate(fd_cap, 0); CHECK_RESULT(ftruncate, CAP_FTRUNCATE, ret == 0); ret = openat(dirfd, "cap_ftruncate", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDONLY); CHECK_RESULT(openat(O_TRUNC | O_RDONLY), CAP_FTRUNCATE | CAP_READ | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_WRONLY); CHECK_RESULT(openat(O_TRUNC | O_WRONLY), CAP_FTRUNCATE | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDWR); CHECK_RESULT(openat(O_TRUNC | O_RDWR), CAP_FTRUNCATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(unlinkat(dirfd, "cap_ftruncate", 0) == 0); ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY, 0600); CHECK_RESULT(openat(O_CREATE | O_WRONLY), CAP_CREATE | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0); ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR, 0600); CHECK_RESULT(openat(O_CREATE | O_RDWR), CAP_CREATE | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0); ret = openat(dirfd, "cap_fsync", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY); CHECK_RESULT(openat(O_FSYNC | O_WRONLY), CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR); CHECK_RESULT(openat(O_FSYNC | O_RDWR), CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY); CHECK_RESULT(openat(O_SYNC | O_WRONLY), CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR); CHECK_RESULT(openat(O_SYNC | O_RDWR), CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0); CHECK(ret == -1 || close(ret) == 0); CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0); /* * Note: this is not expected to work over NFS. */ ret = fchflags(fd_cap, UF_NODUMP); CHECK_RESULT(fchflags, CAP_FCHFLAGS, ret == 0 || (is_nfs && errno == EOPNOTSUPP)); ret = openat(dirfd, "cap_chflagsat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0); CHECK_RESULT(chflagsat, CAP_CHFLAGSAT | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_chflagsat", 0) == 0); ret = fchown(fd_cap, -1, -1); CHECK_RESULT(fchown, CAP_FCHOWN, ret == 0); ret = openat(dirfd, "cap_fchownat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = fchownat(dfd_cap, "cap_fchownat", -1, -1, 0); CHECK_RESULT(fchownat, CAP_FCHOWN | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_fchownat", 0) == 0); ret = fchmod(fd_cap, 0644); CHECK_RESULT(fchmod, CAP_FCHMOD, ret == 0); ret = openat(dirfd, "cap_fchmodat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = fchmodat(dfd_cap, "cap_fchmodat", 0600, 0); CHECK_RESULT(fchmodat, CAP_FCHMOD | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_fchmodat", 0) == 0); ret = fcntl(fd_cap, F_GETFL); CHECK_RESULT(fcntl(F_GETFL), CAP_FCNTL, ret >= 0); ret = fcntl(fd_cap, F_SETFL, ret); CHECK_RESULT(fcntl(F_SETFL), CAP_FCNTL, ret == 0); /* XXX flock */ ret = fstat(fd_cap, &sb); CHECK_RESULT(fstat, CAP_FSTAT, ret == 0); ret = openat(dirfd, "cap_fstatat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = fstatat(dfd_cap, "cap_fstatat", &sb, 0); CHECK_RESULT(fstatat, CAP_FSTAT | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_fstatat", 0) == 0); ret = fstatfs(fd_cap, &sf); CHECK_RESULT(fstatfs, CAP_FSTATFS, ret == 0); ret = fpathconf(fd_cap, _PC_NAME_MAX); CHECK_RESULT(fpathconf, CAP_FPATHCONF, ret >= 0); ret = futimes(fd_cap, NULL); CHECK_RESULT(futimes, CAP_FUTIMES, ret == 0); ret = openat(dirfd, "cap_futimesat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = futimesat(dfd_cap, "cap_futimesat", NULL); CHECK_RESULT(futimesat, CAP_FUTIMES | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_futimesat", 0) == 0); ret = openat(dirfd, "cap_linkat_src", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = linkat(dirfd, "cap_linkat_src", dfd_cap, "cap_linkat_dst", 0); CHECK_RESULT(linkat, CAP_LINKAT | CAP_LOOKUP, ret == 0); CHECK(unlinkat(dirfd, "cap_linkat_src", 0) == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_linkat_dst", 0) == 0); ret = mkdirat(dfd_cap, "cap_mkdirat", 0700); CHECK_RESULT(mkdirat, CAP_MKDIRAT | CAP_LOOKUP, ret == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR) == 0); ret = mkfifoat(dfd_cap, "cap_mkfifoat", 0600); CHECK_RESULT(mkfifoat, CAP_MKFIFOAT | CAP_LOOKUP, ret == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_mkfifoat", 0) == 0); ret = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0); CHECK_RESULT(mknodat, CAP_MKNODAT | CAP_LOOKUP, ret == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_mknodat", 0) == 0); /* TODO: renameat(2) */ ret = symlinkat("test", dfd_cap, "cap_symlinkat"); CHECK_RESULT(symlinkat, CAP_SYMLINKAT | CAP_LOOKUP, ret == 0); CHECK(ret == -1 || unlinkat(dirfd, "cap_symlinkat", 0) == 0); ret = openat(dirfd, "cap_unlinkat", O_CREAT, 0600); CHECK(ret >= 0); CHECK(close(ret) == 0); ret = unlinkat(dfd_cap, "cap_unlinkat", 0); CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0); CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", 0) == 0); ret = mkdirat(dirfd, "cap_unlinkat", 0700); CHECK(ret == 0); ret = unlinkat(dfd_cap, "cap_unlinkat", AT_REMOVEDIR); CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0); CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", AT_REMOVEDIR) == 0); pollfd.fd = fd_cap; pollfd.events = POLLIN | POLLERR | POLLHUP; pollfd.revents = 0; ret = poll(&pollfd, 1, 0); if (rights & CAP_EVENT) CHECK((pollfd.revents & POLLNVAL) == 0); else CHECK((pollfd.revents & POLLNVAL) != 0); /* XXX: select, kqueue */ close(fd_cap); close(fd_capcap); if (success == -1) { fprintf(stderr, "No tests for rights 0x%jx.\n", (uintmax_t)rights); success = FAILED; } return (success); }
int main(void) { char dname_buf[] = "/tmp/test-mmap.XXXXXX"; char *dname; int dir_fd; int file_fd; struct stat st[5]; /* check whether *at(2) syscalls are available */ dir_fd = openat(AT_FDCWD, "/", O_DIRECTORY|O_RDONLY); if (dir_fd == -1 && errno == ENOSYS) return EXIT_SUCCESS; /* kernel too old */ assert(dir_fd != -1); close(dir_fd); /* create a tree like * / * +- tmp/ * +- <tmpname>/ * |- test/ * |- some-file * +- some-link -> some-file */ dname = mkdtemp(dname_buf); assert(dname != NULL); dir_fd = open(dname, O_DIRECTORY|O_RDONLY); assert(dir_fd != -1); TEST(mkdirat(dir_fd, "test", 0700)); TEST(chdir(dname)); TEST(chdir("test")); file_fd = openat(dir_fd, "some-file", O_WRONLY|O_CREAT, 0400); assert(file_fd != -1); write(file_fd, "some text\n", 10); TEST(close(file_fd)); TEST(symlinkat("some-file", dir_fd, "some-link")); TEST(symlinkat("dangling", dir_fd, "dangling-link")); /* now check, whether attributes of 'some-file' and 'some-link' * returned by stat(2), lstat(2) and fstatat(2) are consistent */ TEST(stat("../some-file", &st[0])); TEST(lstat("../some-link", &st[1])); TEST(fstatat(dir_fd, "some-file", &st[2], 0)); TEST(fstatat(dir_fd, "some-link", &st[3], AT_SYMLINK_NOFOLLOW)); TEST(fstatat(dir_fd, "some-link", &st[4], 0)); TEST(faccessat(dir_fd, "some-file", R_OK, 0)); TEST((faccessat(dir_fd, "some-file", W_OK, 0) == -1 && errno == EACCES) ? 0 : -1);; if (1) fputs("skipping faccessat(..., AT_SYMLINK_NOFOLLOW) checks for now...\n", stderr); else { /* this is broken for dietlibc; the 'flags' parameter is not checked * by the kernel but must be handled by the libc itself */ TEST(faccessat(dir_fd, "some-link", W_OK, AT_SYMLINK_NOFOLLOW)); TEST(faccessat(dir_fd, "dangling-link", R_OK, AT_SYMLINK_NOFOLLOW)); } assert(st[0].st_mode == (0400 | S_IFREG)); assert(S_ISLNK(st[1].st_mode)); TEST(memne(&st[0], &st[1])); TEST(memeq(&st[0], &st[2])); TEST(memeq(&st[0], &st[4])); TEST(memeq(&st[1], &st[3])); /* and cleanup the mess... */ TEST(unlinkat(dir_fd, "some-link", 0)); TEST(unlinkat(dir_fd, "some-file", 0)); TEST(unlinkat(dir_fd, "dangling-link", 0)); TEST(unlinkat(dir_fd, "test", AT_REMOVEDIR)); TEST(rmdir(dname)); return EXIT_SUCCESS; }
static fsal_status_t makesymlink(struct fsal_obj_handle *dir_hdl, const char *name, const char *link_path, struct attrlist *attrib, struct fsal_obj_handle **handle) { struct vfs_fsal_obj_handle *myself, *hdl; int dir_fd = -1; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int flags = O_PATH | O_NOACCESS; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); LogDebug(COMPONENT_FSAL, "create %s", name); *handle = NULL; /* poison it first */ if (!dir_hdl->obj_ops.handle_is(dir_hdl, DIRECTORY)) { LogCrit(COMPONENT_FSAL, "Parent handle is not a directory. hdl = 0x%p", dir_hdl); return fsalstat(ERR_FSAL_NOTDIR, 0); } myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; goto hdlerr; } dir_fd = vfs_fsal_open(myself, flags, &fsal_error); if (dir_fd < 0) return fsalstat(fsal_error, -dir_fd); flags |= O_NOFOLLOW; /* BSD needs O_NOFOLLOW for * fhopen() of symlinks */ retval = vfs_stat_by_handle(dir_fd, myself->handle, &stat, flags); if (retval < 0) { retval = errno; goto direrr; } /* Become the user because we are creating an object in this dir. */ fsal_set_credentials(op_ctx->creds); retval = symlinkat(link_path, dir_fd, name); if (retval < 0) { retval = errno; fsal_restore_ganesha_credentials(); goto direrr; } fsal_restore_ganesha_credentials(); retval = vfs_name_to_handle(dir_fd, dir_hdl->fs, name, fh); if (retval < 0) { retval = errno; goto linkerr; } /* now get attributes info, * being careful to get the link, not the target */ retval = fstatat(dir_fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; goto linkerr; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(dir_fd, fh, dir_hdl->fs, &stat, NULL, name, op_ctx->fsal_export); if (hdl == NULL) { retval = ENOMEM; goto linkerr; } *handle = &hdl->obj_handle; close(dir_fd); return fsalstat(ERR_FSAL_NO_ERROR, 0); linkerr: unlinkat(dir_fd, name, 0); direrr: close(dir_fd); hdlerr: if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); }
void copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid, gid_t gid, int flags) { char *p, lnk[MAXPATHLEN], copybuf[4096]; int len, homefd, srcfd, destfd; ssize_t sz; struct stat st; struct dirent *e; DIR *d; if (*dir == '/') dir++; if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) { warn("mkdir(%s)", dir); return; } fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW); if (flags > 0) chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW); if (skelfd == -1) return; homefd = openat(rootfd, dir, O_DIRECTORY); if ((d = fdopendir(skelfd)) == NULL) { close(skelfd); close(homefd); return; } while ((e = readdir(d)) != NULL) { if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; p = e->d_name; if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1) continue; if (strncmp(p, "dot.", 4) == 0) /* Conversion */ p += 3; if (S_ISDIR(st.st_mode)) { copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY), st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags); continue; } if (S_ISLNK(st.st_mode) && (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1)) != -1) { lnk[len] = '\0'; symlinkat(lnk, homefd, p); fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW); continue; } if (!S_ISREG(st.st_mode)) continue; if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1) continue; destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL, st.st_mode); if (destfd == -1) { close(srcfd); continue; } while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0) write(destfd, copybuf, sz); close(srcfd); /* * Propagate special filesystem flags */ fchown(destfd, uid, gid); fchflags(destfd, st.st_flags); close(destfd); } closedir(d); }
static int do_test (void) { /* fdopendir takes over the descriptor, make a copy. */ int dupfd = dup (dir_fd); if (dupfd == -1) { puts ("dup failed"); return 1; } if (lseek (dupfd, 0, SEEK_SET) != 0) { puts ("1st lseek failed"); return 1; } /* The directory should be empty safe the . and .. files. */ DIR *dir = fdopendir (dupfd); if (dir == NULL) { puts ("fdopendir failed"); return 1; } struct dirent64 *d; while ((d = readdir64 (dir)) != NULL) if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { printf ("temp directory contains file \"%s\"\n", d->d_name); return 1; } closedir (dir); /* Try to create a file. */ int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666); if (fd == -1) { if (errno == ENOSYS) { puts ("*at functions not supported"); return 0; } puts ("file creation failed"); return 1; } write (fd, "hello", 5); puts ("file created"); struct stat64 st1; if (fstat64 (fd, &st1) != 0) { puts ("fstat64 failed"); return 1; } close (fd); if (symlinkat ("some-file", dir_fd, "another-file") != 0) { puts ("symlinkat failed"); return 1; } struct stat64 st2; if (fstatat64 (dir_fd, "some-file", &st2, 0) != 0) { puts ("fstatat64 failed"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { puts ("file changed after symlinkat"); return 1; } if (fstatat64 (dir_fd, "another-file", &st2, AT_SYMLINK_NOFOLLOW) != 0) { puts ("2nd fstatat64 failed"); return 1; } if (!S_ISLNK (st2.st_mode)) { puts ("2nd fstatat64 does not show file is a symlink"); return 1; } if (fstatat64 (dir_fd, "another-file", &st2, 0) != 0) { puts ("3rd fstatat64 failed"); return 1; } if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino || st1.st_size != st2.st_size) { puts ("stat results do not match"); return 1; } if (unlinkat (dir_fd, "another-file", 0) != 0) { puts ("unlinkat failed"); return 1; } if (unlinkat (dir_fd, "some-file", 0) != 0) { puts ("2nd unlinkat failed"); return 1; } close (dir_fd); return 0; }
static gboolean checkout_file_from_input_at (OstreeRepo *self, OstreeRepoCheckoutOptions *options, GFileInfo *file_info, GVariant *xattrs, GInputStream *input, int destination_dfd, const char *destination_name, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; int res; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) { do res = symlinkat (g_file_info_get_symlink_target (file_info), destination_dfd, destination_name); while (G_UNLIKELY (res == -1 && errno == EINTR)); if (res == -1) { glnx_set_error_from_errno (error); goto out; } if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) { if (G_UNLIKELY (fchownat (destination_dfd, destination_name, g_file_info_get_attribute_uint32 (file_info, "unix::uid"), g_file_info_get_attribute_uint32 (file_info, "unix::gid"), AT_SYMLINK_NOFOLLOW) == -1)) { glnx_set_error_from_errno (error); goto out; } if (xattrs) { if (!glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name, xattrs, cancellable, error)) goto out; } } } else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { g_autoptr(GOutputStream) temp_out = NULL; int fd; guint32 file_mode; file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); /* Don't make setuid files on checkout when we're doing --user */ if (options->mode == OSTREE_REPO_CHECKOUT_MODE_USER) file_mode &= ~(S_ISUID|S_ISGID); do fd = openat (destination_dfd, destination_name, O_WRONLY | O_CREAT | O_EXCL, file_mode); while (G_UNLIKELY (fd == -1 && errno == EINTR)); if (fd == -1) { glnx_set_error_from_errno (error); goto out; } temp_out = g_unix_output_stream_new (fd, TRUE); fd = -1; /* Transfer ownership */ if (!write_regular_file_content (self, options, temp_out, file_info, xattrs, input, cancellable, error)) goto out; } else g_assert_not_reached (); ret = TRUE; out: return ret; }
static unsigned int call_syscall(struct syscall_desc *scall, char *argv[]) { struct stat64 sb; long long flags; unsigned int i; char *endp; int name, rval; union { char *str; long long num; } args[MAX_ARGS]; #ifdef HAS_FREEBSD_ACL int entry_id = ACL_FIRST_ENTRY; acl_t acl, newacl; acl_entry_t entry, newentry; #endif /* * Verify correctness of the arguments. */ for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { if (scall->sd_args[i] == TYPE_NONE) { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) break; fprintf(stderr, "too many arguments [%s]\n", argv[i]); exit(1); } else { if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { if (scall->sd_args[i] & TYPE_OPTIONAL) break; fprintf(stderr, "too few arguments\n"); exit(1); } if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { if (strcmp(argv[i], "NULL") == 0) args[i].str = NULL; else if (strcmp(argv[i], "DEADCODE") == 0) args[i].str = (void *)0xdeadc0de; else args[i].str = argv[i]; } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { args[i].num = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { if (strcmp(argv[i], "AT_FDCWD") == 0) { args[i].num = AT_FDCWD; } else if (strcmp(argv[i], "BADFD") == 0) { /* In case AT_FDCWD is -1 on some systems... */ if (AT_FDCWD == -1) args[i].num = -2; else args[i].num = -1; } else { int pos; pos = strtoll(argv[i], &endp, 0); if (*endp != '\0' && !isspace((unsigned char)*endp)) { fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); exit(1); } args[i].num = descriptor_get(pos); } } } } /* * Call the given syscall. */ #define NUM(n) (args[(n)].num) #define STR(n) (args[(n)].str) switch (scall->sd_action) { case ACTION_OPEN: flags = str2flags(open_flags, STR(1)); if (flags & O_CREAT) { if (i == 2) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = open(STR(0), (int)flags, (mode_t)NUM(2)); } else { if (i == 3) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = open(STR(0), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_OPENAT: flags = str2flags(open_flags, STR(2)); if (flags & O_CREAT) { if (i == 3) { fprintf(stderr, "too few arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3)); } else { if (i == 4) { fprintf(stderr, "too many arguments\n"); exit(1); } rval = openat(NUM(0), STR(1), (int)flags); } if (rval >= 0) descriptor_add(rval); break; case ACTION_CREATE: rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1)); if (rval >= 0) close(rval); break; case ACTION_UNLINK: rval = unlink(STR(0)); break; case ACTION_UNLINKAT: rval = unlinkat(NUM(0), STR(1), (int)str2flags(unlinkat_flags, STR(2))); break; case ACTION_MKDIR: rval = mkdir(STR(0), (mode_t)NUM(1)); break; case ACTION_MKDIRAT: rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_RMDIR: rval = rmdir(STR(0)); break; case ACTION_LINK: rval = link(STR(0), STR(1)); break; case ACTION_LINKAT: rval = linkat(NUM(0), STR(1), NUM(2), STR(3), (int)str2flags(linkat_flags, STR(4))); break; case ACTION_SYMLINK: rval = symlink(STR(0), STR(1)); break; case ACTION_SYMLINKAT: rval = symlinkat(STR(0), NUM(1), STR(2)); break; case ACTION_RENAME: rval = rename(STR(0), STR(1)); break; case ACTION_RENAMEAT: rval = renameat(NUM(0), STR(1), NUM(2), STR(3)); break; case ACTION_MKFIFO: rval = mkfifo(STR(0), (mode_t)NUM(1)); break; case ACTION_MKFIFOAT: rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2)); break; case ACTION_MKNOD: case ACTION_MKNODAT: { mode_t ntype; dev_t dev; int fa; switch (scall->sd_action) { case ACTION_MKNOD: fa = 0; break; case ACTION_MKNODAT: fa = 1; break; default: abort(); } dev = makedev(NUM(fa + 3), NUM(fa + 4)); if (strcmp(STR(fa + 1), "c") == 0) /* character device */ ntype = S_IFCHR; else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ ntype = S_IFBLK; else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ ntype = S_IFIFO; else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ ntype = S_IFDIR; else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ ntype = S_IFREG; else { fprintf(stderr, "wrong argument 1\n"); exit(1); } switch (scall->sd_action) { case ACTION_MKNOD: rval = mknod(STR(0), ntype | NUM(2), dev); break; case ACTION_MKNODAT: rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); break; default: abort(); } break; } case ACTION_BIND: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_BINDAT case ACTION_BINDAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CONNECT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #ifdef HAS_CONNECTAT case ACTION_CONNECTAT: { struct sockaddr_un sunx; sunx.sun_family = AF_UNIX; strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1); sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; rval = socket(AF_UNIX, SOCK_STREAM, 0); if (rval < 0) break; rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx, sizeof(sunx)); break; } #endif case ACTION_CHMOD: rval = chmod(STR(0), (mode_t)NUM(1)); break; case ACTION_FCHMOD: rval = fchmod(NUM(0), (mode_t)NUM(1)); break; #ifdef HAS_LCHMOD case ACTION_LCHMOD: rval = lchmod(STR(0), (mode_t)NUM(1)); break; #endif case ACTION_FCHMODAT: rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2), str2flags(fchmodat_flags, STR(3))); break; case ACTION_CHOWN: rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWN: rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_LCHOWN: rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); break; case ACTION_FCHOWNAT: rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3), (int)str2flags(fchownat_flags, STR(4))); break; #ifdef HAS_CHFLAGS case ACTION_CHFLAGS: rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_FCHFLAGS case ACTION_FCHFLAGS: rval = fchflags(NUM(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif #ifdef HAS_CHFLAGSAT case ACTION_CHFLAGSAT: rval = chflagsat(NUM(0), STR(1), (unsigned long)str2flags(chflags_flags, STR(2)), (int)str2flags(chflagsat_flags, STR(3))); break; #endif #ifdef HAS_LCHFLAGS case ACTION_LCHFLAGS: rval = lchflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1))); break; #endif case ACTION_TRUNCATE: rval = truncate64(STR(0), NUM(1)); break; case ACTION_FTRUNCATE: rval = ftruncate64(NUM(0), NUM(1)); break; case ACTION_STAT: rval = stat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTAT: rval = fstat64(NUM(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_LSTAT: rval = lstat64(STR(0), &sb); if (rval == 0) { show_stats(&sb, STR(1)); return (i); } break; case ACTION_FSTATAT: rval = fstatat(NUM(0), STR(1), &sb, (int)str2flags(fstatat_flags, STR(2))); if (rval == 0) { show_stats(&sb, STR(3)); return (i); } break; case ACTION_PATHCONF: case ACTION_FPATHCONF: case ACTION_LPATHCONF: { long lrval; name = str2name(pathconf_names, STR(1)); if (name == -1) { fprintf(stderr, "unknown name %s", STR(1)); exit(1); } errno = 0; switch (scall->sd_action) { case ACTION_PATHCONF: lrval = pathconf(STR(0), name); break; case ACTION_FPATHCONF: lrval = fpathconf(NUM(0), name); break; case ACTION_LPATHCONF: lrval = lpathconf(STR(0), name); break; default: abort(); } if (lrval == -1 && errno == 0) { printf("unlimited\n"); return (i); } else if (lrval >= 0) { printf("%ld\n", lrval); return (i); } rval = -1; break; } #ifdef HAS_FREEBSD_ACL case ACTION_PREPENDACL: rval = -1; acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) break; newacl = acl_from_text(STR(1)); if (acl == NULL) break; while (acl_get_entry(newacl, entry_id, &newentry) == 1) { entry_id = ACL_NEXT_ENTRY; if (acl_create_entry_np(&acl, &entry, 0)) break; if (acl_copy_entry(entry, newentry)) break; } rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl); break; case ACTION_READACL: acl = acl_get_file(STR(0), ACL_TYPE_NFS4); if (acl == NULL) rval = -1; else rval = 0; break; #endif case ACTION_WRITE: rval = write(NUM(0), STR(1), strlen(STR(1))); break; default: fprintf(stderr, "unsupported syscall\n"); exit(1); } #undef STR #undef NUM if (rval < 0) { const char *serrno; serrno = err2str(errno); fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); printf("%s\n", serrno); exit(1); } printf("0\n"); return (i); }
static void mkdir_home_parents(int dfd, const char *dir) { struct stat st; char *dirs, *tmp; if (*dir != '/') errx(EX_DATAERR, "invalid base directory for home '%s'", dir); dir++; if (fstatat(dfd, dir, &st, 0) != -1) { if (S_ISDIR(st.st_mode)) return; errx(EX_OSFILE, "root home `/%s' is not a directory", dir); } dirs = strdup(dir); if (dirs == NULL) errx(EX_UNAVAILABLE, "out of memory"); tmp = strrchr(dirs, '/'); if (tmp == NULL) { free(dirs); return; } tmp[0] = '\0'; /* * This is a kludge especially for Joerg :) * If the home directory would be created in the root partition, then * we really create it under /usr which is likely to have more space. * But we create a symlink from cnf->home -> "/usr" -> cnf->home */ if (strchr(dirs, '/') == NULL) { asprintf(&tmp, "usr/%s", dirs); if (tmp == NULL) errx(EX_UNAVAILABLE, "out of memory"); if (mkdirat(dfd, tmp, _DEF_DIRMODE) != -1 || errno == EEXIST) { fchownat(dfd, tmp, 0, 0, 0); symlinkat(tmp, dfd, dirs); } free(tmp); } tmp = dirs; if (fstatat(dfd, dirs, &st, 0) == -1) { while ((tmp = strchr(tmp + 1, '/')) != NULL) { *tmp = '\0'; if (fstatat(dfd, dirs, &st, 0) == -1) { if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1) err(EX_OSFILE, "'%s' (root home parent) is not a directory", dirs); } *tmp = '/'; } } if (fstatat(dfd, dirs, &st, 0) == -1) { if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1) err(EX_OSFILE, "'%s' (root home parent) is not a directory", dirs); fchownat(dfd, dirs, 0, 0, 0); } free(dirs); }
int main(int argc, char *argv[]) { char *targetdir = ".", *target = NULL; int ret = 0, sflag = 0, fflag = 0, dirfd = AT_FDCWD, hastarget = 0, flags = AT_SYMLINK_FOLLOW; struct stat st, tst; ARGBEGIN { case 'f': fflag = 1; break; case 'L': flags |= AT_SYMLINK_FOLLOW; break; case 'P': flags &= ~AT_SYMLINK_FOLLOW; break; case 's': sflag = 1; break; default: usage(); } ARGEND if (!argc) usage(); if (argc > 1) { if (!stat(argv[argc - 1], &st) && S_ISDIR(st.st_mode)) { if ((dirfd = open(argv[argc - 1], O_RDONLY)) < 0) eprintf("open %s:", argv[argc - 1]); targetdir = argv[argc - 1]; if (targetdir[strlen(targetdir) - 1] == '/') targetdir[strlen(targetdir) - 1] = '\0'; } else if (argc == 2) { hastarget = 1; target = argv[argc - 1]; } else { eprintf("%s: not a directory\n", argv[argc - 1]); } argv[argc - 1] = NULL; argc--; } for (; *argv; argc--, argv++) { if (!hastarget) target = basename(*argv); if (!sflag) { if (stat(*argv, &st) < 0) { weprintf("stat %s:", *argv); ret = 1; continue; } else if (fstatat(dirfd, target, &tst, AT_SYMLINK_NOFOLLOW) < 0) { if (errno != ENOENT) { weprintf("fstatat %s %s:", targetdir, target); ret = 1; continue; } } else if (st.st_dev == tst.st_dev && st.st_ino == tst.st_ino) { if (!fflag) { weprintf("%s and %s/%s are the same file\n", *argv, targetdir, target); ret = 1; } continue; } } if (fflag && unlinkat(dirfd, target, 0) < 0 && errno != ENOENT) { weprintf("unlinkat %s %s:", targetdir, target); ret = 1; continue; } if ((sflag ? symlinkat(*argv, dirfd, target) : linkat(AT_FDCWD, *argv, dirfd, target, flags)) < 0) { weprintf("%s %s <- %s/%s:", sflag ? "symlinkat" : "linkat", *argv, targetdir, target); ret = 1; } } return ret; }
int symlink(const char* old_path, const char* new_path) { return symlinkat(old_path, AT_FDCWD, new_path); }