Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Noitidart/f05ffde7dcaffe792a4d to your computer and use it in GitHub Desktop.
Save Noitidart/f05ffde7dcaffe792a4d to your computer and use it in GitHub Desktop.
_ff-addon-snippet-LibC_fcntl - Working on getting fcntl to work to detect if profile is locked. (js-ctypes)
Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/osfile.jsm');
function doit() {
if (OS.Constants.Sys.Name == 'Darwin') {
var _libc = ctypes.open('libc.dylib');
} else if (OS.Constants.Sys.Name == 'Linux') {
var _libc = ctypes.open('libc.so.6');
}
var lockFilePath = OS.Path.join(OS.Constants.Path.profileDir, '.parentlock');
var lockFilePath = '/Users/noi/Library/Application Support/Firefox/Profiles/6myop6y5.Unnamed Profile 1/.parentlock';
var lockFilePath = '/home/noi/.mozilla/firefox/b51cfon3.Unnamed Profile 1/.parentlock'; //up1
//var lockFilePath = '/home/noi/.mozilla/firefox/eb0nz6yr.Unnamed Profile 2/.parentlock'; //up2
//var lockFilePath = '/home/noi/.mozilla/firefox/qydytdfk.default/.parentlock'; //main
//var lockFilePath = '/home/noi/.mozilla/firefox/q0rlb7ap.Unnamed Profile 1/.parentlock'; //dev
console.log(lockFilePath);
///////////////fcntl
if (OS.Constants.Sys.Name == 'Darwin') {
var F_GETLK = 7;
var F_RDLCK = 1;
var F_WRLCK = 3;
var F_UNLCK = 2;
/* https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
* struct flock {
* off_t l_start; // starting offset
* off_t l_len; // len = 0 means until end of file
* pid_t l_pid; // lock owner
* short l_type; // lock type: read/write, etc.
* short l_whence; // type of l_start
* };
*/
//order matters:
// http://chat.stackexchange.com/transcript/message/17822233#17822233
// https://ask.mozilla.org/question/1134/order-of-strcuture-matters-test-case-flock-for-use-by-fcntl/
var flock = new ctypes.StructType('flock', [
{'l_start': ctypes.unsigned_long},
{'l_len': ctypes.unsigned_long},
{'l_pid': ctypes.int},
{'l_type': ctypes.unsigned_short},
{'l_whence': ctypes.unsigned_short}
]);
} else if (OS.Constants.Sys.Name == 'Linux') {
var F_GETLK = 5;
var F_RDLCK = 0;
var F_WRLCK = 1;
var F_UNLCK = 2;
/* http://linux.die.net/man/2/fcntl
* typedef struct flock {
* ...
* short l_type; //Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
* short l_whence; //How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END
* off_t l_start; //Starting offset for lock
* off_t l_len; //Number of bytes to lock
* pid_t l_pid; //PID of process blocking our lock (F_GETLK only)
* ...
* };
*/
//order matters:
// http://chat.stackexchange.com/transcript/message/17822233#17822233
// https://ask.mozilla.org/question/1134/order-of-strcuture-matters-test-case-flock-for-use-by-fcntl/
var flock = new ctypes.StructType('flock', [
{'l_type': ctypes.unsigned_short},
{'l_whence': ctypes.unsigned_short},
{'l_start': ctypes.unsigned_long},
{'l_len': ctypes.unsigned_long},
{'l_pid': ctypes.int}
]);
}
//int fcntl(int fd, int cmd, ... /* arg */ );
/*
* int fcntl(int fd, int cmd);
* int fcntl(int fd, int cmd, long arg);
* int fcntl(int fd, int cmd, struct flock *lock);
*/
var fcntl = _libc.declare('fcntl',
ctypes.default_abi,
ctypes.int,
ctypes.int,
ctypes.int,
flock.ptr
);
//int open(const char *pathname, int flags, mode_t mode);
//https://github.com/downthemall/downthemall-mirror/blob/c8fd56c464b2af6b8dc7ddee1f9bbe6e9f6e8382/modules/manager/worker_posix.js#L35
var openFd = _libc.declare(
"open",
ctypes.default_abi,
ctypes.int, // retval
ctypes.char.ptr, // path
ctypes.int // flags
);
var closeFd = _libc.declare(
"close",
ctypes.default_abi,
ctypes.int, // retval
ctypes.int // fd
);
var filepath = lockFilePath;
//filepath = OS.Path.join(OS.Constants.Path.desktopDir, 'new.txt');
let fd = openFd(filepath, OS.Constants.libc.O_RDWR); //setting this to O_RDWR fixes errno of 9 on fcntl
if (fd == -1) {
//if file does not exist and O_CREAT was not set. errno is == 2
//if file is a dangling symbolic link. errno is == 2
console.error('failed to open file, fd:', fd, 'errno:', ctypes.errno);
return -1;
} else {
console.log('successfully opened, fd:', fd)
}
try {
var testlock = new flock();
testlock.l_type = F_WRLCK; //can use F_RDLCK but keep openFd at O_RDWR, it just works
testlock.l_start = 0;
testlock.l_whence = OS.Constants.libc.SEEK_SET;
testlock.l_len = 0;
var rez = fcntl(fd, F_GETLK, testlock.address());
console.log('rez:', rez);
if (rez != -1) {
//check testlock.l_type
console.log('testlock:', uneval(testlock));
if (testlock.l_type == F_UNLCK) {
//can also test if testlock.l_pid is not 0
console.info('file is NOT locked');
} else if (testlock.l_type == F_WRLCK) {
console.info('file is WRITE LOCKED, it may be read locked too');
} else if (testlock.l_type == F_RDLCK) {
console.info('file is NOT write locked but just READ LOCKED'); //we know this because testlock tested for write lock first
} else {
console.error('testlock.l_type is unknown, l_type:', testlock.l_type);
}
} else {
console.log('rez was -1, errno', ctypes.errno);
}
} finally {
var rez = closeFd(fd);
if (rez == 0) {
//console.log('succesfully closed, rez:', rez);
} else {
console.error('FAILED to close, rez:', rez, 'errno', ctypes.errno);
}
}
}
console.time('flock');
doit();
console.timeEnd('flock');
@Noitidart
Copy link
Author

README

Rev1

Rev2

  • Commit to save
  • Brought in some constants from places, links are commented in code

Rev3

  • Commit to save
  • Using openFd and changed close to closeFd, may not need pipe

Rev4

  • Tested code and got it to run without logic errors
  • However fnctl is always returning -1

Rev5

Rev6

Rev7

  • The errno of 9 came back, fixed it by putting O_RDWR on .open

Rev8

  • Oh my gosh figured out why it wasn't working. F_GETLK was set to wrong constant, I set it to 7 (per this guy here and he's wrong!!) it should be 5 I figured this out by using the following C code:

    #include <sys/types.h>  
    #include <unistd.h>      
    #include <fcntl.h>
    #include <stdio.h>
    
    int main() {
      int fd;
      struct flock lock, savelock;
    
      printf("F_GETLK: %d\n", F_GETLK);
      printf("F_WRLCK: %d\n", F_WRLCK);
    
      fd = open("/home/noi/.mozilla/firefox/b51cfon3.Unnamed Profile 1/.parentlock", O_RDWR);
      printf("fd = %d\n", fd);
    
      lock.l_type = F_WRLCK;
      lock.l_start = 0;
      lock.l_whence = SEEK_SET;
      lock.l_len = 0;
    
      savelock = lock;
    
      int code = fcntl(fd, F_GETLK, &lock);
    
      printf("fcntl return codeee: %d\n", code);
      printf("lock.l_pid: %d\n", lock.l_pid);
      printf("lock.l_type: %d\n", lock.l_type);
    
      exit(0);
    }
    • also this guy here got the constant right
  • HOWEVER now the issue is that the order of flock matters per OS it looks like

  • ALSO running this code on the .parentlock of the file of the current profile always returns that it is NOT locked because it is the same process BUT this is expected behavior, it also matches the behavior of nsIToolkitProfileService.lockProfilePath

    • Even the l_pid field of flock is not populated with pid when checking .parentlock of profile running the code from, but obviously if you are running code from a profile you already know the profile is in use. To make fcntl work right you have to run from other process, so can maybe get it to shell from popen or something crap Im guessing

Rev9

  • Man all my F_RDLCK, F_WRLCK, and F_UNLCK constnats were messed up, and it looks like even the guy that got F_GETLK contant right didn't get the these three constants right, I figured them out by using the C code above to dump them.
    • The SEEK_* constants were right
    • I'm thinking that these people I'm getting the constnats from are .py and they seem to have their own fcntl.py implementation so the constants are different for that reason MAYBE

Rev10

  • Fixed constant values (based on ubuntu c code)
  • Added timing, taking 0.35ms!

Rev11

  • Fixed logic, if l_type of testlock is returned as F_UNLCK then the file is NOT locked, before it thought it was locked but this was not correct
  • Figured out that fcntl constants vary based on OS (maybe/probably the libc library)
    • Asked on mozillazine if I can ust constants by name in js-ctypes instead of by value HERE

Rev12

  • Programmed multi-OS support, for Linux, and Mac OS (constants and structure and library) (well library just for libc.so.6)
    • I am making the assumption that for all Linux's the constants and structure of flock are same based on HERE
  • Switched to using OS.Constants.libc.SEEK_SET as I found that was available

Rev12

  • Fixed typo, it was importing lib.so.6 for mac os too, fixed it too dylib

Rev13

  • Renamed to included LibC_ in name

@yajd
Copy link

yajd commented Sep 24, 2014

for mac, i had to set l_pid to ctpyes.int otherwies it would throw ctypes.errno == 22 which is EINVAL weidr.

Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/osfile.jsm');

function doit() {
    var _libc = ctypes.open('libc.dylib');


    //var lockFilePath = OS.Path.join(OS.Constants.Path.profileDir, '.parentlock');
    var lockFilePath = '/Users/noi/Library/Application Support/Firefox/Profiles/6myop6y5.Unnamed Profile 1/.parentlock';
    //var lockFilePath = '/home/noi/.mozilla/firefox/b51cfon3.Unnamed Profile 1/.parentlock'; //up1
    //var lockFilePath = '/home/noi/.mozilla/firefox/eb0nz6yr.Unnamed Profile 2/.parentlock'; //up2
    //var lockFilePath = '/home/noi/.mozilla/firefox/qydytdfk.default/.parentlock'; //main
    //var lockFilePath = '/home/noi/.mozilla/firefox/q0rlb7ap.Unnamed Profile 1/.parentlock'; //dev
    console.log(lockFilePath);

    ///////////////fcntl

    /*
     * typedef struct flock {
     * ...
     * short l_type;     //Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
     * short l_whence;   //How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END
     * off_t l_start;    //Starting offset for lock
     * off_t l_len;      //Number of bytes to lock
     * pid_t l_pid;      //PID of process blocking our lock (F_GETLK only) 
     * ...
     * };
     */
    //https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
    //order matters for mac i guess: http://chat.stackexchange.com/transcript/message/17822233#17822233
    var flock = new ctypes.StructType('flock', [
        {'l_start': ctypes.unsigned_long},
        {'l_len': ctypes.unsigned_long},
        {'l_pid': ctypes.int},
        {'l_type': ctypes.unsigned_short},
        {'l_whence': ctypes.unsigned_short}
    ]);


    //int fcntl(int fd, int cmd, ... /* arg */ );
    /*
     * int fcntl(int fd, int cmd);
     * int fcntl(int fd, int cmd, long arg);
     * int fcntl(int fd, int cmd, struct flock *lock);
     */
    var fcntl = _libc.declare('fcntl',
        ctypes.default_abi,
        ctypes.int,
        ctypes.int,
        ctypes.int,
        flock.ptr
    );

    //int open(const char *pathname, int flags, mode_t mode);
    //https://github.com/downthemall/downthemall-mirror/blob/c8fd56c464b2af6b8dc7ddee1f9bbe6e9f6e8382/modules/manager/worker_posix.js#L35
    var openFd = _libc.declare(
        "open",
        ctypes.default_abi,
        ctypes.int, // retval
        ctypes.char.ptr, // path
        ctypes.int // flags
    );

    var closeFd = _libc.declare(
        "close",
        ctypes.default_abi,
        ctypes.int, // retval
        ctypes.int // fd
    );

    var F_GETLK = 7;
    var F_RDLCK = 1;
    var F_WRLCK = 3;
    var F_UNLCK = 2;
    var SEEK_SET = 0;
    var SEEK_CUR = 1;
    var SEEK_END = 2;

    var filepath = lockFilePath;
    //filepath = OS.Path.join(OS.Constants.Path.desktopDir, 'new.txt');
    var fd = openFd(filepath, OS.Constants.libc.O_RDWR); //setting this to O_RDWR fixes errno of 9 on fcntl
    if (fd == -1) {
        //if file does not exist and O_CREAT was not set. errno is == 2
        //if file is a dangling symbolic link. errno is == 2
        console.error('failed to open file, fd:', fd, 'errno:', ctypes.errno);
        return -1;
    } else {
        console.log('successfully opened, fd:', fd)
    }
    try {
        var testlock = new flock();
        testlock.l_type    = F_WRLCK; //can use F_RDLCK but keep openFd at O_RDWR, it just works
        testlock.l_start   = 0;
        testlock.l_whence  = SEEK_SET;
        testlock.l_len     = 0;

        ctypes.errno = 0;
        console.log('errno:', ctypes.errno);
        var rez = fcntl(fd, F_GETLK, testlock.address());
        console.log('rez:', rez);
        if (rez != -1) {
            //check testlock.l_type
            console.log('testlock:', uneval(testlock));
            if (testlock.l_type == F_UNLCK) {
                //can also test if testlock.l_pid is not 0
                console.info('file is NOT locked');
            } else if (testlock.l_type == F_WRLCK) {
                console.info('file is WRITE LOCKED, it may be read locked too');
            } else if (testlock.l_type == F_RDLCK) {
                console.info('file is NOT write locked but just READ LOCKED'); //we know this because testlock tested for write lock first
            } else {
                console.error('testlock.l_type is unknown, l_type:', testlock.l_type);
            }
        } else {
            console.log('rez was -1, errno', ctypes.errno);
        }
    } finally {
        var rez = closeFd(fd);
        if (rez == 0) {
            //console.log('succesfully closed, rez:', rez);
        } else {
            console.error('FAILED to close, rez:', rez, 'errno', ctypes.errno);
        }
    }

}

console.time('flock');
doit();
console.timeEnd('flock');

@Noitidart
Copy link
Author

When using the libc constants follow this commentary to figure out field order:

noida   btw guys if short is 2 what is off_t and pid_t?
11:27   noida   8?
11:27       *** avikpal quit (Ping timeout: 121 seconds)
11:27   jdm noida: http://stackoverflow.com/questions/9073667/where-to-find-the-complete-definition-of-off-t-type
11:29   noida   so they say blkcnt_t and off_t shall be signed integer types.
11:35   noida   jdm in ctypes to get size of platform dependent signed integer do you go ctypes.size_t.size?

11:37   noida   ah so maybe harshil__ is on 64bit system thats why he's getting these numbers:
11:37   noida   FLOCK_L_LEN:16 L_TYPE:0 L_PID:24 L_WHENCE:2 L_START: 8
11:37   jdm noida: yep, makes sense
11:37   harshil__   yes my os is 64bit
11:37   noida   super this is awesome!
11:38   noida   so to find offset of field in structure i take that number and divide by size of the type?
11:39   jdm noida: no, you multiply the offset in bytes by *
11:39   jdm er, by 8
11:39   jdm actually I'm not sure what you
11:39   jdm you're asking
11:39       *** Fallen|away is now known as Fallen
11:39   noida   these offsets are supposed to help me figure out how to create teh structure
11:40   noida   for example in mac flock structure is this:https://gist.github.com/Noitidart/f05ffde7dcaffe792a4d#file-_ff-addon-snippet-fcntl-js-L40
11:40   jdm ah
11:40   noida   and in ubuntu the flock structure has the same fields but in different order: see line 67 of that
11:41   jdm so the offset of a field will show how many bytes should have preceded it
11:41   noida   oh!!
11:42   jdm if you sort them in ascending order, that's the field order
11:42   jdm and then you sort out the types that will take up that many bytes
11:42   noida   ohhh!!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment