OSDN Git Service

Merge remote-tracking branch 'toybox/master' into HEAD
[android-x86/external-toybox.git] / lib / lib.c
index 718ea3a..6f7ed30 100644 (file)
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -547,16 +547,20 @@ void poke(void *ptr, uint64_t val, int size)
 }
 
 // Iterate through an array of files, opening each one and calling a function
-// on that filehandle and name.  The special filename "-" means stdin if
-// flags is O_RDONLY, stdout otherwise.  An empty argument list calls
+// on that filehandle and name. The special filename "-" means stdin if
+// flags is O_RDONLY, stdout otherwise. An empty argument list calls
 // function() on just stdin/stdout.
 //
 // Note: pass O_CLOEXEC to automatically close filehandles when function()
-// returns, otherwise filehandles must be closed by function()
-void loopfiles_rw(char **argv, int flags, int permissions, int failok,
+// returns, otherwise filehandles must be closed by function().
+// pass WARN_ONLY to produce warning messages about files it couldn't
+// open/create, and skip them. Otherwise function is called with fd -1.
+void loopfiles_rw(char **argv, int flags, int permissions,
   void (*function)(int fd, char *name))
 {
-  int fd;
+  int fd, failok = !(flags&WARN_ONLY);
+
+  flags &= ~WARN_ONLY;
 
   // If no arguments, read from stdin.
   if (!*argv) function((flags & O_ACCMODE) != O_RDONLY ? 1 : 0, "-");
@@ -564,8 +568,8 @@ void loopfiles_rw(char **argv, int flags, int permissions, int failok,
     // Filename "-" means read from stdin.
     // Inability to open a file prints a warning, but doesn't exit.
 
-    if (!strcmp(*argv, "-")) fd=0;
-    else if (0>(fd = open(*argv, flags, permissions)) && !failok) {
+    if (!strcmp(*argv, "-")) fd = 0;
+    else if (0>(fd = notstdio(open(*argv, flags, permissions))) && !failok) {
       perror_msg_raw(*argv);
       continue;
     }
@@ -574,10 +578,10 @@ void loopfiles_rw(char **argv, int flags, int permissions, int failok,
   } while (*++argv);
 }
 
-// Call loopfiles_rw with O_RDONLY|O_CLOEXEC and !failok (common case).
+// Call loopfiles_rw with O_RDONLY|O_CLOEXEC|WARN_ONLY (common case)
 void loopfiles(char **argv, void (*function)(int fd, char *name))
 {
-  loopfiles_rw(argv, O_RDONLY|O_CLOEXEC, 0, 0, function);
+  loopfiles_rw(argv, O_RDONLY|O_CLOEXEC|WARN_ONLY, 0, function);
 }
 
 // Slow, but small.
@@ -636,11 +640,18 @@ int copy_tempfile(int fdin, char *name, char **tempname)
   if (!tempfile2zap) sigatexit(tempfile_handler);
   tempfile2zap = *tempname;
 
-  // Set permissions of output file
+  // Set permissions of output file (ignoring errors, usually due to nonroot)
 
   fstat(fdin, &statbuf);
   fchmod(fd, statbuf.st_mode);
 
+  // We chmod before chown, which strips the suid bit. Caller has to explicitly
+  // switch it back on if they want to keep suid.
+
+  // I said IGNORING ERRORS. Both gcc and clang clutch their pearls about this
+  // but it's _supposed_ to fail when we're not root.
+  if (fchown(fd, statbuf.st_uid, statbuf.st_gid)) fd = fd;
+
   return fd;
 }
 
@@ -1184,3 +1195,47 @@ int regexec0(regex_t *preg, char *string, long len, int nmatch,
     len -= ll;
   }
 }
+
+// Return user name or string representation of number, returned buffer
+// lasts until next call.
+char *getusername(uid_t uid)
+{
+  struct passwd *pw = bufgetpwuid(uid);
+  static char unum[12];
+
+  sprintf(unum, "%u", (unsigned)uid);
+  return pw ? pw->pw_name : unum;
+}
+
+// Return group name or string representation of number, returned buffer
+// lasts until next call.
+char *getgroupname(gid_t gid)
+{
+  struct group *gr = bufgetgrgid(gid);
+  static char gnum[12];
+
+  sprintf(gnum, "%u", (unsigned)gid);
+  return gr ? gr->gr_name : gnum;
+}
+
+// Iterate over lines in file, calling function. Function can write 0 to
+// the line pointer if they want to keep it, or 1 to terminate processing,
+// otherwise line is freed. Passed file descriptor is closed at the end.
+void do_lines(int fd, void (*call)(char **pline, long len))
+{
+  FILE *fp = fd ? xfdopen(fd, "r") : stdin;
+
+  for (;;) {
+    char *line = 0;
+    ssize_t len;
+
+    len = getline(&line, (void *)&len, fp);
+    if (len > 0) {
+      call(&line, len);
+      if (line == (void *)1) break;
+      free(line);
+    } else break;
+  }
+
+  if (fd) fclose(fp);
+}